home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 July: Technology Seed / ADC Seed CD - July 1999.toast / USB / Mac OS USB DDK v1.2 / Examples / PrinterClassDriver / PrinterClassDriver.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-04-15  |  107.8 KB  |  3,334 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        PrinterClassDriver.c
  3.  
  4.     Contains:    MacOS USB printer class driver
  5.                 [ref. IEEE Std 1284-1994]
  6.  
  7.     Version:    xxx put version here xxx
  8.  
  9.  
  10.  
  11.     Copyright:    1998 by Apple Computer, Inc., all rights reserved.
  12.  
  13. */
  14.  
  15.  
  16. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  17.     includes
  18.   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  19. #include <Gestalt.h>
  20. #include <Devices.h>
  21. #include <DriverServices.h>
  22. #include <Interrupts.h>
  23. #include <LowMem.h>
  24. #include <Folders.h>
  25. #include <String.h>
  26. #include <stdio.h>
  27. #include <USB.h>
  28.  
  29. #ifndef __CODEFRAGMENTS__
  30. #include <codefragments.h>
  31. #endif
  32.  
  33. #include "PrinterClassDriver.h"
  34. #include "TradDriverLoaderLib.h"
  35.  
  36. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  37.     constants
  38.   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  39. #define MAX_SUFFIX                    127                    // maximum copies we'll enter in unit table
  40. #define kUSBParallelDrvrRsrcID        12
  41. #define kMinDrvrUnitNumber            48                    // minimum unit table entry which we'll install
  42. #define kUSS720MillisecondDelay        3*1000                // poll every three seconds
  43. #define kUSS720StatusMSDelay        100                    // poll ten times per second
  44. #define MAX_USB_TRANSFER_SIZE        TRANSFER_SIZE        // zero acts as manifest for conditional compilation
  45.  
  46. #define kUSBAttributeBulk            0x02
  47. #define kUSBInputEndpointMask        0x80
  48.  
  49. enum
  50. {
  51.     kUSBv12    =    0x01200000
  52. };
  53.  
  54. enum
  55. {
  56.     kCString = 0,                // StateStr, USBStatusStr selector
  57.     kPString,                    // StateStr, USBStatusStr selector
  58.     kDrvrFirstDigit = 5            // length_byte + ".USB" = 5
  59. };
  60. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  61.     manifest constants
  62. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  63. //
  64. //    DEBUGGING                        extra debugging information to USB Expert Log
  65. //    DOUBLE_BUFFER                    use a page aligned buffer in system heap to double buffer app i/o
  66. //    LOG                                echo all the write data to a log file in the system folder
  67. // LOCK_MEMORY                        LockMemory on the i/o buffer before write and unlock on write completion
  68. // VIRTUAL_MEMORY_CHECK            check the physical addresses of the buffer we pass for write requests
  69. // MACSBUG_ON_READ                break into MacsBug before each read request
  70. //    MACSBUG_ON_READ_COMPLETE    break into MacsBug at each read completion routine
  71. //    MACSBUG_ON_WRITE                break into MacsBug on each write request
  72. // MACSBUG_ON_WRITE_COMPLETE    break into MacsBug at each write completion routine
  73. //
  74. #define DEBUGGING                        0    /* DEBUGGING */
  75. #define DOUBLE_BUFFER                    1    /* DOUBLE_BUFFER */
  76. #define LOG                                0    /* LOG */
  77. #define LOCK_MEMORY                        1    /* LOCK_MEMORY */
  78. #define MACSBUG_ON_READ                    0    /* MACSBUG_ON_READ */
  79. #define MACSBUG_ON_READ_COMPLETE        0    /* MACSBUG_ON_READ_COMPLETE */ 
  80. #define MACSBUG_ON_WRITE                0    /* MACSBUG_ON_WRITE */
  81. #define MACSBUG_ON_WRITE_COMPLETE        0    /* MACSBUG_ON_WRITE_COMPLETE */ 
  82. #define VIRTUAL_MEMORY_CHECK            0    /* VIRTUAL_MEMORY_CHECK require LOCK_MEMORY, currently broken */
  83.  
  84. #if LOG
  85. #define LOGGING(x)    x
  86. #include <stdio.h>
  87. #else
  88. #define LOGGING(x)
  89. #endif
  90.  
  91. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  92.     globals
  93.   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  94. static struct usbPrinterPBStruct    printerClassRecord;
  95. static FSSpec                            printerClassDriverFileSpec;
  96. LOGGING( static FILE                    *logfile );
  97. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  98.     prototypes
  99.   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  100.  
  101. static void    PrinterDeviceCompletionProc(USBPB *pb);
  102. static void SetNullUSBParamBlock( USBDeviceRef dev, USBPB *pb );
  103. static void    SoftReset( USBPB *usbprint, short interfaceNum );
  104. static void    CapabilityRequest( USBPB *pb, Ptr p, long length, short config, short interfaceNum, short alternateSetting );
  105. static void    CentronicsStatus( USBPB *usbprint, Ptr p, short interfaceNum );
  106. static void CompletionProc(USBPB *pb);
  107.  
  108. void            PrinterDeviceInitiateTransaction(USBPB *pb);
  109.  
  110. OSErr            CFMInitialization( CFragInitBlock *initBlock );
  111.  
  112. Boolean    gUSBVersionNeedsBulkFixPresent;
  113.  
  114. void        CheckUSBVersion(void);
  115. OSStatus     SecondaryUSBBulkRead(void *pb, void *result);
  116. OSStatus     SecondaryUSBBulkWrite(void *pb, void *result);
  117. OSStatus     SafeUSBBulkRead(USBPB *pb);
  118. OSStatus     SafeUSBBulkWrite(USBPB *pb);
  119.  
  120. void    CheckUSBVersion(void)
  121. {
  122. OSStatus    err;
  123. UInt32        usbVersion;
  124.  
  125.     err = Gestalt('usbv', (long*)&usbVersion);
  126.     if (err == noErr)
  127.         gUSBVersionNeedsBulkFixPresent = (usbVersion < kUSBv12);
  128. }
  129.  
  130. OSStatus SecondaryUSBBulkRead(void *pb, void *result)
  131. {
  132.     *(OSStatus*)result = USBBulkRead((USBPB*)pb);
  133.     return noErr;
  134. }
  135.  
  136. OSStatus SecondaryUSBBulkWrite(void *pb, void *result)
  137. {
  138.     *(OSStatus*)result = USBBulkWrite((USBPB*)pb);
  139.     return noErr;
  140. }
  141.  
  142. OSStatus SafeUSBBulkRead(USBPB *pb)
  143. {
  144.     OSStatus    result;
  145.  
  146.     if (gUSBVersionNeedsBulkFixPresent)
  147.     {
  148.         // Use CallSecondaryInterruptHandler2 to call USBBulkRead if
  149.         // less than USB v1.2 present
  150.         CallSecondaryInterruptHandler2(SecondaryUSBBulkRead, nil, pb, &result);
  151.     }
  152.     else
  153.         result = USBBulkRead(pb);
  154.         
  155.     return result;
  156. }
  157.  
  158. OSStatus SafeUSBBulkWrite(USBPB *pb)
  159. {
  160.     OSStatus    result;
  161.  
  162.     if (gUSBVersionNeedsBulkFixPresent)
  163.     {
  164.         // Use CallSecondaryInterruptHandler2 to call USBBulkWrite if
  165.         // less than USB v1.2 present
  166.         CallSecondaryInterruptHandler2(SecondaryUSBBulkWrite, nil, pb, &result);
  167.     }
  168.     else
  169.         result = USBBulkWrite(pb);
  170.         
  171.     return result;
  172. }
  173.  
  174.  
  175.  
  176.  
  177. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  178.     Name:        HexString8
  179.  
  180.     Input Parameters:    
  181.         v                unsigned long value
  182.         
  183.     Output Parameters:
  184.         p                8 bytes: hex string representing value
  185.         
  186.     Description:
  187.  
  188.  
  189.  
  190. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  191. static void
  192. HexString8( unsigned long v, unsigned char *p )
  193. {
  194.     int    shift;
  195.     
  196.     for ( shift = 32-4; shift >= 0; shift -= 4 )
  197.     {
  198.         char c = (v >> shift) & 0x0F;
  199.         *p++ = c + (c > 9? ('A'-10): '0');
  200.     }
  201. }
  202.  
  203. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  204.     Name:        hexstr
  205.  
  206.     Input Parameters:    
  207.         count                number of bytes
  208.         p                    pointer to bytes
  209.         
  210.     Output Parameters:
  211.         q                    hex dump of data
  212.         
  213.     Description:
  214.  
  215.  
  216.  
  217. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  218. void hexstr( int count, char *p, char *q )
  219. {
  220.     char *s = p;
  221.     int i = count;
  222.     for ( ; count > 0; --count, ++p )
  223.     {
  224.         int hi, lo;
  225.         hi = (*p >> 4)& 0x0F;
  226.         lo = *p & 0x0F;
  227.         *q++ = '0';
  228.         *q++ = 'x';
  229.         *q++ = hi + (hi > 9? 'A' - 10: '0');
  230.         *q++ = lo + (lo > 9? 'A' - 10: '0');
  231.         *q++ = ' ';
  232.     }
  233.     for ( ; i > 0; --i, ++s )
  234.         *q++ = *s < ' ' || *s > 0x7E? '.': *s;
  235. }
  236.  
  237.  
  238. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  239.     Name:        USBStatusStr
  240.  
  241.     Input Parameters:    
  242.         usbStatus            usb error code
  243.         kind                    kPString or kCString
  244.         
  245.     Output Parameters:
  246.         unsigned char *    description of error (c-string or p-string)
  247.  
  248.     Description:
  249.         a simple mapping of errors to human-readable form
  250.  
  251.  
  252.  
  253.  
  254.  
  255. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  256. static unsigned char *
  257. USBStatusStr( OSStatus usbStatus, int kind )
  258. {
  259.     unsigned char *p;
  260.  
  261.     switch ( usbStatus )
  262.     {
  263.         case    kUSBInternalErr:                    p = "\p" kStrPrinterClass "Internal error"; break;
  264.         case    kUSBUnknownDeviceErr:                p = "\p" kStrPrinterClass "Unknown device"; break;
  265.         case    kUSBUnknownPipeErr:                 p = "\p" kStrPrinterClass "Unknown pipe"; break;
  266.         case    kUSBTooManyPipesErr:                p = "\p" kStrPrinterClass "Too many pipes"; break;
  267.         case    kUSBIncorrectTypeErr:                p = "\p" kStrPrinterClass "Incorrect type"; break;
  268.         case    kUSBRqErr:                            p = "\p" kStrPrinterClass "Request error"; break;
  269.         case    kUSBUnknownRequestErr:                p = "\p" kStrPrinterClass "Unknown request"; break;
  270.         case    kUSBTooManyTransactionsErr:            p = "\p" kStrPrinterClass "Too many transactions"; break;
  271.         case    kUSBAlreadyOpenErr:                    p = "\p" kStrPrinterClass "Already open"; break;
  272.         case    kUSBNoDeviceErr:                    p = "\p" kStrPrinterClass "No device"; break;
  273.         case    kUSBDeviceErr:                        p = "\p" kStrPrinterClass "Device error"; break;
  274.         case    kUSBOutOfMemoryErr:                    p = "\p" kStrPrinterClass "Out of memory"; break;
  275.         case    kUSBNotFound:                        p = "\p" kStrPrinterClass "Not found"; break;
  276.         case    kUSBLinkErr:                        p = "\p" kStrPrinterClass "Link Err"; break;
  277.         case    kUSBCRCErr:                            p = "\p" kStrPrinterClass "Comms/Device err, bad CRC";  break;        
  278.         case    kUSBBitstufErr:                        p = "\p" kStrPrinterClass "Comms/Device err, bitstuffing"; break;        
  279.         case    kUSBDataToggleErr:                    p = "\p" kStrPrinterClass "Comms/Device err, Bad data toggle"; break;        
  280.         case    kUSBEndpointStallErr:                p = "\p" kStrPrinterClass "Device didn't understand"; break;        
  281.         case    kUSBNotRespondingErr:                p = "\p" kStrPrinterClass "No device, device hung"; break;        
  282.         case    kUSBPIDCheckErr:                    p = "\p" kStrPrinterClass "Comms/Device err, PID CRC error"; break;        
  283.         case    kUSBWrongPIDErr:                    p = "\p" kStrPrinterClass "Comms/Device err, Bad or wrong PID"; break;        
  284.         case    kUSBOverRunErr:                        p = "\p" kStrPrinterClass "Packet too large or more data than buffer"; break;        
  285.         case    kUSBUnderRunErr:                    p = "\p" kStrPrinterClass "Less data than buffer"; break;        
  286.         case    kUSBRes1Err:                        p = "\p" kStrPrinterClass "kUSBRes1Err"; break;        
  287.         case    kUSBRes2Err:                        p = "\p" kStrPrinterClass "kUSBRes1Err"; break;        
  288.         case    kUSBBufOvrRunErr:                    p = "\p" kStrPrinterClass "Buffer over run error"; break;        
  289.         case    kUSBBufUnderRunErr:                    p = "\p" kStrPrinterClass "Buffer under run error"; break;        
  290.         case    kUSBNotSent1Err:                    p = "\p" kStrPrinterClass "Transaction not sent1"; break;        
  291.         case    kUSBNotSent2Err:                    p = "\p" kStrPrinterClass "Transaction not sent2"; break;    
  292.         default:
  293.             p = "\p" kStrPrinterClass "Unknown error nnnnnnnn";
  294.             HexString8( usbStatus, p + *p - 8 + 1 );
  295.             break;
  296.     }
  297.     
  298.     return kind == kPString? p: p + 1;
  299. }
  300.  
  301. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  302.     Name:        StateStr
  303.  
  304.     Input Parameters:    
  305.         usbRefCon            usb error code
  306.         kind                    kPString or kCString
  307.         
  308.     Output Parameters:
  309.         unsigned char *    description of state (c-string or p-string)
  310.  
  311.     Description:
  312.         a simple mapping of states to human-readable form
  313.  
  314.  
  315.  
  316.  
  317.  
  318. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  319. static unsigned char *
  320. StateStr( OSStatus refCon, int kind )
  321. {
  322.     unsigned char *p;
  323.  
  324.     refCon &= ~(kTransactionPending | kRetryTransaction | kReturnFromDriver);
  325.     switch ( refCon )
  326.     {
  327.         case kUndefined:                            p = "\p" kStrPrinterClass "kUndefined"; break;
  328.         case kNilCompletion:                        p = "\p" kStrPrinterClass "kNilCompletion"; break;
  329.  
  330.         case kFindInterface_bidirectional:            p = "\p" kStrPrinterClass "kFindInterface_bidirectional"; break;
  331.         case kFindInterface_unidirectional:            p = "\p" kStrPrinterClass "kFindInterface_unidirectional"; break;
  332.         case kOpenDevice:                            p = "\p" kStrPrinterClass "kOpenDevice"; break;
  333.         case kNewInterfaceRef:                        p = "\p" kStrPrinterClass "kNewInterfaceRef"; break;
  334.  
  335.         case kSetInterface:                            p = "\p" kStrPrinterClass "kSetInterface"; break;
  336.         case kConfigureInterface:                    p = "\p" kStrPrinterClass "kConfigureInterface"; break;
  337.         case kGetCapabilityString:                    p = "\p" kStrPrinterClass "kGetCapabilityString"; break;
  338.         case kDelayGetCapability:                    p = "\p" kStrPrinterClass "kDelayGetCapability"; break;
  339.  
  340.         case kAllocateCapabilityMem:                p = "\p" kStrPrinterClass "kAllocateCapabilityMem"; break;
  341.         case kGetFullCapabilityString:                p = "\p" kStrPrinterClass "kGetFullCapabilityString"; break;
  342.         case kGetInterface:                            p = "\p" kStrPrinterClass "kGetInterface"; break;
  343.         case kFindBulkOutPipe:                        p = "\p" kStrPrinterClass "kFindBulkOutPipe"; break;
  344.  
  345.         case kFindBulkInPipe:                        p = "\p" kStrPrinterClass "kFindBulkInPipe"; break;
  346.         case kTaskTimeRequired:                        p = "\p" kStrPrinterClass "kTaskTimeRequired"; break;
  347.  
  348.         case kGetCentronicsStatus:                    p = "\p" kStrPrinterClass "kGetCentronicsStatus"; break;
  349.         case kDelayGetCentronicsStatus:                p = "\p" kStrPrinterClass "kDelayGetCentronicsStatus"; break;
  350.  
  351.         case kDeallocateCapbilityString:            p = "\p" kStrPrinterClass "kDeallocateCapbilityString"; break;
  352.         default:
  353.             p = "\p" kStrPrinterClass "Unknown state nnnnnnnn";
  354.             HexString8( refCon, p + *p - 8 + 1 );
  355.             break;
  356.     }
  357.     return kind == kPString? p: p + 1;    
  358. }
  359.  
  360. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  361.     Name:        HiHex
  362.  
  363.     Input Parameters:    
  364.         v                        only low byte used
  365.         
  366.     Output Parameters:
  367.         <function result>    high nibble represented as ASCII char
  368.         
  369.     Description:
  370.  
  371.  
  372.  
  373. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  374. static unsigned char
  375. HiHex( int v )
  376. {
  377.     unsigned char    hinibble = (v >> 4) & 0x0f;
  378.     return hinibble + ((hinibble > 9)? ('A'-10): '0');
  379. }
  380.  
  381. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  382.     Name:        LoHex
  383.  
  384.     Input Parameters:    
  385.         v                        only low byte used
  386.         
  387.     Output Parameters:
  388.         <function result>    low nibble represented as ASCII char
  389.         
  390.     Description:
  391.  
  392.  
  393.  
  394. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  395. static unsigned char
  396. LoHex( int v )
  397. {
  398.     unsigned char    lonibble = v & 0x0f;
  399.     return lonibble + ((lonibble > 9)? ('A'-10): '0');
  400. }
  401.  
  402. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  403.     Name:        immediateError
  404.  
  405.     Input Parameters:    
  406.         
  407.     Output Parameters:
  408.         
  409.     Description:
  410.  
  411.  
  412.  
  413. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  414. static Boolean
  415. immediateError(OSStatus err)
  416. {
  417.     return((err != kUSBPending) && (err != noErr) );
  418. }
  419.  
  420. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  421.     Name:        SetNullUSBParamBlock
  422.  
  423.     Input Parameters:    
  424.         pb                    pointer to USB parameter block
  425.         dev                USB device reference
  426.     Output Parameters:
  427.         pb                    all fields set to default values
  428.  
  429.     Description:
  430.         setup a USB parameter block for use by the current device
  431.  
  432.  
  433.  
  434.  
  435. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  436. static void
  437. SetNullUSBParamBlock( USBDeviceRef dev, USBPB *pb )
  438. {
  439.     pb->qlink = NULL;
  440.     pb->qType = 0;
  441.     pb->pbLength = sizeof(USBPB);
  442.     pb->pbVersion = kUSBCurrentPBVersion;
  443.     pb->usbFlags = 0;
  444.     pb->usbStatus = noErr;
  445.     pb->usbCompletion = (USBCompletion) NULL;
  446.  
  447.     pb->usbReference = dev;
  448. }
  449.  
  450.  
  451. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  452.     Name:        ParseCapability
  453.  
  454.     Input Parameters:    
  455.         capability            pointer to 1284-1994 capability string
  456.         attribute            pointer to c-string key we're retrieving (terminate with colon)
  457.         *result_length        maximum length of the result 
  458.         
  459.     Output Parameters:
  460.         result                c-string which followed the key and was terminated by semi-colon
  461.                                 (semi-colon has been stripped)
  462.         *result_length        actual length of the result (may be zero)
  463.     
  464.     Description:
  465.         Search for "attribute" in the 1284 "capability" string
  466.         The identifier is terminated with a semi-colon
  467.  
  468.         Return the attribute in result
  469.             null-string if attribute not found.
  470.  
  471.  
  472.  
  473.  
  474. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  475. static void
  476. ParseCapability(
  477.     unsigned char    *capability,
  478.     unsigned char    *attribute,
  479.     unsigned char    *result,
  480.     int                *result_length 
  481. )
  482. {
  483.     //
  484.     //    search for "attribute" in the 1284 "capability" string
  485.     //
  486.     //    the identifier is terminated with a semi-colon
  487.     //
  488.     //    return the attribute in result
  489.     //            null-string if attribute not found
  490.     //
  491.     //    <to do> skip blanks, isolate colon, skip blanks
  492.     //
  493.     int                source_length,
  494.                         target_length;
  495.     unsigned char    *source,
  496.                         *target,
  497.                         *destination;
  498.     //
  499.     //    begin a brute force search
  500.     //
  501.     source = attribute;
  502.     source_length = CStrLen((char *)attribute );
  503.  
  504.     target = capability + 2;    // skip the length
  505.     target_length =  capability[1] | (capability[0] << 8);
  506.     target_length -= 2;            // don't count the length
  507.     while ( target_length >= source_length )
  508.     {
  509.         if ( memcmp( source, target, source_length ) == 0 )
  510.             break;
  511.         --target_length;
  512.         ++target;
  513.     }
  514.  
  515.     destination = result;
  516.     *destination = 0;    // empty result
  517.  
  518.     target += source_length;
  519.     target_length -= source_length;    // skip the attribute string
  520.  
  521.     if ( target_length > 0 )
  522.     {
  523.         //
  524.         //    we found the attribute in the capability string
  525.         //
  526.         while ( destination - result < *result_length )    // arbitrarily limit reply
  527.         {
  528.             if ( *target == ';' )
  529.                 break;
  530.             *destination++ = *target++;        // copy a byte of attribute over
  531.         }
  532.         *destination++ = '\0';                        // trailing NUL
  533.         *result_length = destination - result;    // report the length of the data (with trailing NUL)
  534.     }
  535. }
  536.  
  537.  
  538. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  539.     Name:        GetClass
  540.  
  541.     Input Parameters:    
  542.         capability            pointer to 1284-1994 capability string
  543.         *result_length        maximum length of the result 
  544.         
  545.     Output Parameters:
  546.         result                c-string extracted from the MODEL key
  547.         *result_length        actual length of the result  (may be zero)
  548.         
  549.     Description:
  550.         CLASS is a Microsoft extension to the 1284-capability string
  551.         if we don't find it
  552.             we assume that the device is a printer
  553.         Since the USB hardware has already indicated this, we're really allowing
  554.         devices which aren't printers to be reached via the DRVRs we've installed.
  555.  
  556.  
  557.  
  558.  
  559. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  560. static void
  561. GetClass(
  562.     unsigned char    *capability,
  563.     unsigned char    *result,
  564.     int                *result_length
  565. )
  566. {
  567.     //
  568.     //    We supply the upper-case PRINTER to be consistent with 1284-1994
  569.     //        if we don't find a class.
  570.     //
  571.     ParseCapability( capability, (unsigned char *) "CLASS:", result, result_length);
  572.     if ( *result == '\0' )
  573.         ParseCapability( capability, (unsigned char *) "CLS:", result, result_length);
  574.     if ( *result == '\0' )
  575.         CStrCopy( (char *)result, "PRINTER" );
  576. }
  577.  
  578.  
  579. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  580.     Name:        GetModel
  581.  
  582.     Input Parameters:    
  583.         capability            pointer to 1284-1994 capability string
  584.         *result_length        maximum length of the result 
  585.         
  586.     Output Parameters:
  587.         result                c-string extracted from the MODEL key
  588.         *result_length        actual length of the result  (may be zero)
  589.             
  590.     Description:
  591.         MODEL is a required field of the 1284-capability string
  592.         MODEL may be abbreviated MDL
  593.  
  594.  
  595.  
  596.  
  597. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  598. static void
  599. GetModel(
  600.     unsigned char    *capability, 
  601.     unsigned char    *result,
  602.     int                *result_length
  603. )
  604. {
  605.     //
  606.     //    Most manufacturers abbreviate, so we search for MDL first
  607.     //
  608.     ParseCapability( capability, (unsigned char *) "MDL:", result, result_length );
  609.     if ( *result == '\0' )
  610.         ParseCapability( capability, (unsigned char *) "MODEL:", result, result_length );
  611. }
  612.  
  613.  
  614. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  615.     Name:        GetCommandSet
  616.  
  617.     Input Parameters:    
  618.         
  619.     Output Parameters:
  620.         
  621.     Description:
  622.  
  623.  
  624.  
  625.  
  626. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  627. static void
  628. GetCommandSet(
  629.     unsigned char *capability, 
  630.     unsigned char *result,
  631.     int *result_length
  632. )
  633. {
  634.     //
  635.     //    COMMAND-SET is a required field of the 1284-capability string
  636.     //    COMMAND-SET may be abbreviated CMD
  637.     //
  638.     ParseCapability( capability, (unsigned char *) "CMD:", result, result_length );
  639.     if ( *result == '\0' )
  640.         ParseCapability( capability, (unsigned char *) "COMMAND SET:", result, result_length );
  641. }
  642.  
  643. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  644.     Name:        GetManufacturer
  645.  
  646.     Input Parameters:    
  647.         
  648.     Output Parameters:
  649.         
  650.     Description:
  651.  
  652.  
  653.  
  654. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  655. static void
  656. GetManufacturer(
  657.     unsigned char *capability, 
  658.     unsigned char *result,
  659.     int *result_length
  660. )
  661. {
  662.     //
  663.     //    MANUFACTURER is a required field of the 1284-capability string
  664.     //    MANUFACTURER may be abbreviated MFG
  665.     //
  666.     ParseCapability( capability, (unsigned char *) "MFG:", result, result_length );
  667.     if ( *result == '\0' )
  668.         ParseCapability( capability, (unsigned char *) "MANUFACTURER:", result, result_length );
  669.     if ( *result == '\0' )
  670.         ParseCapability( capability, (unsigned char *) "HMFG:", result, result_length );
  671. }
  672.  
  673.  
  674. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  675.     Name:        DeregisterDevice
  676.  
  677.     Input Parameters:    
  678.         pPrinterPB
  679.  
  680.     Output Parameters:
  681.         <none>
  682.         
  683.     Description:
  684.         remove the device from the name registry
  685.  
  686.  
  687.  
  688.  
  689. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  690. #define kMinNameLength    27
  691. #define kMinModelLength    25
  692. #define kMinClassLength    23
  693.  
  694. static OSStatus
  695. DeregisterDevice( struct usbPrinterPBStruct *pPrinterPB )
  696. {
  697. RegEntryID            self, child, parent;
  698. RegEntryIter         cookie;
  699.  
  700. OSStatus    err;
  701. Str255        tempStr1,tempStr2;
  702. UInt32        nameLength, modelLength,devclassLength;
  703. Boolean     done = false;
  704.  
  705.     USBExpertStatusLevel(5,  pPrinterPB->deviceRef, "\p" kStrPrinterClass "Removing the printer from the name registry", 0 );
  706.     // delete the printer node
  707.     // print out the printer's name (which is the same as the node name)
  708.     nameLength = CStrLen((char *)pPrinterPB->name);
  709.     CStrCopy((char *)tempStr1, (char *)(kStrPrinterClass"Printer name:  "));
  710.     CStrCat((char *)tempStr1, (char *)pPrinterPB->name);
  711.     CStrToPStr((unsigned char *)tempStr2, (char *)tempStr1 );
  712.     USBExpertStatusLevel(5,  pPrinterPB->deviceRef, tempStr2, nameLength );
  713.     
  714.     // locate the model node (parent of printer), and delete it if the printer has no siblings
  715.     if (nameLength<kMinNameLength)
  716.     {
  717.         USBExpertFatalError(pPrinterPB->deviceRef, err, "\p"kStrPrinterClass "Warning!! Printer name string is not long enough!", nameLength);
  718.     }
  719.     else
  720.     {
  721.         RegistryEntryIDInit( &self );
  722.         err = RegistryCStrEntryLookup( nil, (char const *) pPrinterPB->name , &self );
  723.         if ( err == noErr )
  724.         {    
  725.             err = RegistryEntryDelete( &self);
  726.         }
  727.         else
  728.         {
  729.             USBExpertStatusLevel(5,  pPrinterPB->deviceRef, "\p" kStrPrinterClass "Printer node not found!", err );
  730.         }
  731.         RegistryEntryIDDispose(&self);
  732.         
  733.         if (err == noErr &&  pPrinterPB->outRefNum != -1 )
  734.             err = TradRemoveDriver( pPrinterPB->outRefNum, false );
  735.         if (err == noErr &&  pPrinterPB->inRefNum != -1 )
  736.             err = TradRemoveDriver( pPrinterPB->inRefNum, false );
  737.     }
  738.  
  739.  
  740.     // print out the printer's model (which is the same as the node's parent)
  741.     modelLength = CStrLen((char *)pPrinterPB->model);
  742.     CStrCopy((char *)tempStr1, (char *)(kStrPrinterClass"Printer model: "));
  743.     CStrCat((char *)tempStr1, (char *)pPrinterPB->model);
  744.     CStrToPStr((unsigned char *)tempStr2, (char *)tempStr1 );
  745.     USBExpertStatusLevel(5,  pPrinterPB->deviceRef, tempStr2, modelLength );
  746.     
  747.  
  748.     // locate the model node (parent of printer), and delete it if the printer has no siblings
  749.     if (modelLength<kMinModelLength)
  750.     {
  751.         USBExpertFatalError(pPrinterPB->deviceRef, err, "\p"kStrPrinterClass "Warning!! Printer model string is not long enough!", modelLength);
  752.     }
  753.     else
  754.     {
  755.         RegistryEntryIDInit( &parent );
  756.         err = RegistryCStrEntryLookup( nil, (char const *) pPrinterPB->model , &parent );
  757.         if ( err == noErr )
  758.         {    
  759.             RegistryEntryIDInit(&child);
  760.             
  761.             err = RegistryEntryIterateCreate(&cookie);
  762.             if (err == noErr)
  763.                 err = RegistryEntryIterateSet(&cookie, &parent);
  764.             if (err == noErr)
  765.                 err = RegistryEntryIterate(&cookie, kRegIterChildren, &child, &done);
  766.             if ((err == noErr) && done)
  767.             {
  768.                 USBExpertStatusLevel(5,  pPrinterPB->deviceRef, "\p" kStrPrinterClass "No siblings detected, so delete the parent of printer", 0 );
  769.                 err = RegistryEntryDelete(&parent);
  770.             }
  771.             else
  772.             {
  773.                 USBExpertStatusLevel(5,  pPrinterPB->deviceRef, "\p" kStrPrinterClass "Siblings (or error) detected.  Leaving parent in place", err );
  774.             }
  775.             RegistryEntryIterateDispose(&cookie);
  776.         }
  777.         else
  778.         {
  779.             USBExpertStatusLevel(5,  pPrinterPB->deviceRef, "\p" kStrPrinterClass "Parent node not found!", err );
  780.         }
  781.         RegistryEntryIDDispose(&parent);
  782.     }
  783.     
  784.     // print out the printer's model (which is the same as the node's parent)
  785.     devclassLength = CStrLen((char *)pPrinterPB->devclass);
  786.     CStrCopy((char *)tempStr1, (char *)(kStrPrinterClass"Printer class: "));
  787.     CStrCat((char *)tempStr1, (char *)pPrinterPB->devclass);
  788.     CStrToPStr((unsigned char *)tempStr2, (char *)tempStr1 );
  789.     USBExpertStatusLevel(5,  pPrinterPB->deviceRef, tempStr2, devclassLength );
  790.     
  791.  
  792.     // locate the class node (parent of model), and delete it if the class has no siblings
  793.     if (devclassLength<kMinClassLength)
  794.     {
  795.         USBExpertFatalError(pPrinterPB->deviceRef, err, "\p"kStrPrinterClass "Warning!! Printer class string not long enough!", devclassLength);
  796.     }
  797.     else
  798.     {
  799.         RegistryEntryIDInit( &parent );
  800.         err = RegistryCStrEntryLookup( nil, (char const *) pPrinterPB->devclass , &parent );
  801.         if ( err == noErr )
  802.         {    
  803.             RegistryEntryIDInit(&child);
  804.             
  805.             err = RegistryEntryIterateCreate(&cookie);
  806.             if (err == noErr)
  807.                 err = RegistryEntryIterateSet(&cookie, &parent);
  808.             if (err == noErr)
  809.                 err = RegistryEntryIterate(&cookie, kRegIterChildren, &child, &done);
  810.             if ((err == noErr) && done)
  811.             {
  812.                 USBExpertStatusLevel(5,  pPrinterPB->deviceRef, "\p" kStrPrinterClass "No models found, so delete the class node", 0 );
  813.                 err = RegistryEntryDelete(&parent);
  814.             }
  815.             else
  816.             {
  817.                 USBExpertStatusLevel(5,  pPrinterPB->deviceRef, "\p" kStrPrinterClass "Models detected.  Leaving class nodes in place", err );
  818.             }
  819.             RegistryEntryIterateDispose(&cookie);
  820.         }
  821.         else
  822.         {
  823.             USBExpertStatusLevel(5,  pPrinterPB->deviceRef, "\p" kStrPrinterClass "Parent node not found!", err );
  824.         }
  825.         RegistryEntryIDDispose(&parent);
  826.     }
  827.     
  828.     return err;
  829. }
  830.  
  831. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  832.     Name:        RegisterDevice
  833.  
  834.     Input Parameters:    
  835.         pPrinterPB
  836.  
  837.     Output Parameters:
  838.         <none>
  839.         
  840.     Description:
  841.         add the device into the name registry; we can't insert just the node
  842.         if the parent nodes aren't present.
  843.  
  844.         if it isn't present
  845.             insert the device CLASS into the registry
  846.         if it isn't present
  847.             insert the device MODEL into the registry
  848.         finally insert the device itself into the registry
  849.             we're careful to rename multiple devices
  850.  
  851.  
  852.  
  853.  
  854.  
  855.  
  856.  
  857.  
  858.  
  859. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  860. static OSStatus
  861. RegisterDevice( struct usbPrinterPBStruct *pPrinterPB )
  862. {
  863.     //
  864.     //    add the device into the name registry
  865.     //    if it isn't present
  866.     //        insert the device CLASS into the registry
  867.     //    if it isn't present
  868.     //        insert the device MODEL into the registry
  869.     //    finally insert the device itself into the registry
  870.     //        we're careful to rename multiple devices
  871.     //
  872. Str255        identification,
  873.                 devclass,
  874.                 model,
  875.                 commands,
  876.                 tempstr;
  877.                 
  878. RegEntryID    parent, where, self;
  879.  
  880. OSStatus        err;
  881.  
  882. int            model_length,
  883.                 command_length,
  884.                 class_length;
  885.  
  886.  
  887.     USBExpertStatusLevel(5,  pPrinterPB->deviceRef, "\p" kStrPrinterClass "Adding the printer to the name registry", 0 );
  888.     CStrCopy((char *)pPrinterPB->devclass, "");
  889.     CStrCopy((char *)pPrinterPB->model, "");
  890.     CStrCopy((char *)pPrinterPB->name, "");
  891.  
  892.     command_length = sizeof(commands);
  893.     GetCommandSet(pPrinterPB->pCapabilityString, commands, &command_length );
  894.  
  895.  
  896.     // get device class and add it to the name registry.  Typically PRINTER or Printer
  897.     class_length = sizeof(devclass);
  898.     GetClass( pPrinterPB->pCapabilityString, devclass, &class_length );
  899.     
  900.     CStrCopy( (char *)pPrinterPB->devclass, (char *)"Devices:device-tree:" );
  901.     CStrCat( (char *)pPrinterPB->devclass, (char *)devclass );
  902.     
  903.     RegistryEntryIDInit( &where );
  904.     err = RegistryCStrEntryLookup( nil, (char const *) pPrinterPB->devclass, &where );
  905.     if ( err == nrPathNotFound ) 
  906.     {
  907.         //    class not in registry
  908.         //        create a node for all devices of this CLASS
  909.         //
  910.         RegistryEntryIDInit( &parent );
  911.         err = RegistryCStrEntryLookup( nil, "Devices:device-tree:" , &parent );
  912.         if ( err == noErr )
  913.             err = RegistryCStrEntryCreate( nil, (char const *) pPrinterPB->devclass, &where );
  914.         RegistryEntryIDDispose(&parent);
  915.  
  916.     }
  917.     
  918.     CStrToPStr(tempstr, (char *)pPrinterPB->devclass);
  919.     USBExpertStatusLevel(5,  pPrinterPB->deviceRef, tempstr, 0 );
  920.     
  921.     //
  922.     //    add this model into the name registry of this class
  923.     //
  924.     if ( err == noErr )
  925.     {
  926.         model_length = sizeof(model);
  927.         GetModel( pPrinterPB->pCapabilityString, model, &model_length );
  928.         if ( *model != '\0' )
  929.         {
  930.             CStrCopy( (char *)pPrinterPB->model, "Devices:device-tree:" );
  931.             CStrCat( (char *)pPrinterPB->model, (char *)devclass );
  932.             CStrCat( (char *)pPrinterPB->model, ":" );
  933.             if ( *model == '\0'  )
  934.             {
  935.                 CStrCat( (char *)pPrinterPB->model, (char *)"USB_PRINTERCLASS" );
  936.             }
  937.             else
  938.             {
  939.                 CStrCat( (char *)pPrinterPB->model, (char *)model );
  940.             }
  941.             RegistryEntryIDInit( &self );
  942.             err = RegistryCStrEntryLookup( nil, (char const *) pPrinterPB->model , &self );
  943.             if ( err != noErr )
  944.             {
  945.                 // model not in registry
  946.                 err = RegistryCStrEntryCreate( nil, (char const *) pPrinterPB->model, &self );
  947.             }
  948.             
  949.             RegistryEntryIDDispose(&self);
  950.         }
  951.         CStrToPStr(tempstr, (char *)pPrinterPB->model);
  952.         USBExpertStatusLevel(5,  pPrinterPB->deviceRef, tempstr, 0 );
  953.     }
  954.     
  955.     //
  956.     //    add this instance of this model of this class
  957.     //        into the name registry
  958.     //
  959.     if ( *model == '\0'  )
  960.     {
  961.         //
  962.         //    possibly the cable isn't firmly connected or the printer isn't switched on
  963.         //
  964.         err = kUSBInternalErr;
  965.         USBExpertFatalError(pPrinterPB->deviceRef, err, "\p"kStrPrinterClass "Model undefined", 0);
  966.     }
  967.     if ( err == noErr )
  968.     {
  969.         //
  970.         //    start off by identifying the device simply by the model name
  971.         //        increment the numeric suffix until we successfully registry the device
  972.         //
  973.         Str32    suffix;
  974.         int    numeric_suffix;
  975.  
  976.         CStrCopy( (char *)identification, (char *)model );
  977.         RegistryEntryIDInit( &self );
  978.         for ( numeric_suffix = 1; numeric_suffix < MAX_SUFFIX; ++numeric_suffix )
  979.         {
  980.             CStrCopy( (char *)pPrinterPB->name, "Devices:device-tree:" );
  981.             CStrCat( (char *)pPrinterPB->name, (char *)devclass );
  982.             CStrCat( (char *)pPrinterPB->name, ":" );
  983.             CStrCat( (char *)pPrinterPB->name, (char *)model );
  984.             CStrCat( (char *)pPrinterPB->name, ":" );
  985.             CStrCat( (char *)pPrinterPB->name, (char *)identification );
  986.             err = RegistryCStrEntryLookup( nil, (char const *) pPrinterPB->name , &self );
  987.             if ( err != noErr )
  988.             {
  989.                 // enter device in registry
  990.                 err = RegistryCStrEntryCreate( nil, (char const *) pPrinterPB->name, &self );
  991.                 if ( err == noErr )
  992.                     err = RegistryPropertyCreate( &self, "drvrOut", &pPrinterPB->driverOutName, 1 + pPrinterPB->driverOutName[0] );
  993.                 if ( err == noErr )
  994.                     err = RegistryPropertyCreate( &self, "outRef", &pPrinterPB->outRefNum, sizeof(pPrinterPB->outRefNum) );
  995.                 if ( err == noErr )
  996.                     err = RegistryPropertyCreate( &self, "drvrIn", &pPrinterPB->driverInName, 1 + pPrinterPB->driverInName[0] );
  997.                 if ( err == noErr )
  998.                     err = RegistryPropertyCreate( &self, "inRef", &pPrinterPB->inRefNum, sizeof(pPrinterPB->inRefNum) );
  999.                 if ( err == noErr )
  1000.                     err = RegistryPropertyCreate( &self, "privateData", &pPrinterPB, sizeof(pPrinterPB) );
  1001.                 if ( err == noErr )
  1002.                     err = RegistryPropertyCreate( &self, "read", &pPrinterPB->r, sizeof(QueueUSBReadUPP) );
  1003.                 if ( err == noErr )
  1004.                     err = RegistryPropertyCreate( &self, "write", &pPrinterPB->w, sizeof(QueueUSBWriteUPP) );
  1005.                 if ( err == noErr && *commands != '\0' )
  1006.                     err = RegistryPropertyCreate( &self, "command-set", &commands, command_length );
  1007.                 break;
  1008.             }
  1009.             //
  1010.             //    if this name didn't succeed
  1011.             //        try the next numeric suffix
  1012.             //
  1013.             sprintf( (char *)suffix, " %d", numeric_suffix );
  1014.             CStrCopy( (char *)identification, (char *)model );
  1015.             CStrCat( (char *)identification, (char *)suffix );
  1016.         }
  1017.         RegistryEntryIDDispose(&self);
  1018.     }
  1019.     pPrinterPB->printerRegistered = true;
  1020.     
  1021.     CStrToPStr((unsigned char *)tempstr, (char const *)pPrinterPB->name );
  1022.     
  1023.     USBExpertStatusLevel(5,  pPrinterPB->deviceRef, "\p" kStrPrinterClass "Added printer to name registry", 0 );
  1024.     USBExpertStatusLevel(5,  pPrinterPB->deviceRef, tempstr, err );
  1025.     RegistryEntryIDDispose(&where);
  1026.  
  1027.     LOGGING( logfile = fopen( "USBPrinter.log", "wb+" ) );
  1028.     return err;
  1029. }
  1030.  
  1031. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1032.     Name:        LoadResources
  1033.  
  1034.     Input Parameters:
  1035.         pPrinterPB            pointer to class driver's private storage
  1036.         
  1037.     Output Parameters:
  1038.         OSStatus                resource load error
  1039.         
  1040.     Description:
  1041.         Initialize time is the only safe time to to load resources from our file.
  1042.         Here's where we load resources and detach them from the resource manager.
  1043.         Later we'll use these private copies instead of GetResource calls.
  1044.         
  1045.         Using the file spec that we got from the CFMInitialization routine, open
  1046.         our resource fork.
  1047.  
  1048.  
  1049.  
  1050.  
  1051. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1052. static OSStatus
  1053. LoadResources( struct usbPrinterPBStruct *pPrinterPB )
  1054. {
  1055.     short            rf = -1;                // class driver resource fork
  1056.     OSStatus        err;
  1057.  
  1058.     //
  1059.     //    open the resource fork of this class driver
  1060.     //
  1061.     rf = FSpOpenResFile( &printerClassDriverFileSpec,fsRdPerm );
  1062.     err = ResError();
  1063.     
  1064.     //
  1065.     //    load the DRVR that we'll stick in the unit table
  1066.     //
  1067.     pPrinterPB->hDrvr = NULL;
  1068.     if ( err == noErr )
  1069.     {
  1070.         pPrinterPB->hDrvr = (DRVRHeaderHandle) Get1Resource( 'DRVR',  kUSBParallelDrvrRsrcID );
  1071.         if ( pPrinterPB->hDrvr != NULL )
  1072.             DetachResource( (Handle) pPrinterPB->hDrvr );
  1073.         err = ResError();
  1074.     }
  1075.     
  1076.     if ( rf != -1 )
  1077.         CloseResFile( rf );
  1078.     
  1079.     return err;
  1080. }
  1081.  
  1082. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1083.     Name:        InstallDrivers
  1084.  
  1085.     Input Parameters:
  1086.         pPrinterPB
  1087.         
  1088.     Output Parameters:
  1089.         OSStatus            error code
  1090.         
  1091.     Description:
  1092.         install read and write drivers in the unit table
  1093.             we have separate drivers so that we can support a full-duplex protocol
  1094.         rename the driver we just installed (so multiple copies don't conflict)
  1095.         We use the DRVR -refnum-1 so that the driver name has the same hex chars
  1096.             as the driver number (for manual verification in MacsBug)
  1097.  
  1098.  
  1099.  
  1100.  
  1101.  
  1102.  
  1103. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1104. static OSStatus
  1105. InstallDrivers( struct usbPrinterPBStruct *pPrinterPB )
  1106. {
  1107.     //
  1108.     //    install the driver in the unit table
  1109.     //    rename the driver we just installed (so multiple copies don't conflict)
  1110.     //    
  1111.     short            refNum;                // DRVR refNum
  1112.     OSStatus        err =  paramErr;    // couldn't find driver
  1113.  
  1114.     if ( pPrinterPB->hDrvr != NULL )
  1115.         err = TradInstallDriverFromHandle( pPrinterPB->hDrvr, kMinDrvrUnitNumber, TradHighestUnitNumber() + 1, &pPrinterPB->outRefNum );
  1116.  
  1117.     if ( err == noErr )
  1118.     {
  1119.         UnitNumber        unit;
  1120.         DriverFlags        flags;
  1121.         DRVRHeaderPtr    hdr;
  1122.         unsigned char    *suffix,        // append "In" and "Out"
  1123.                             *infix;        // driver reference number follows the ".USB"
  1124.  
  1125.         TradGetDriverInformation( pPrinterPB->outRefNum, &unit, &flags, pPrinterPB->driverOutName, &hdr );
  1126.         BlockMove( pPrinterPB->driverOutName, pPrinterPB->driverInName, 1 + pPrinterPB->driverOutName[0] );
  1127.         
  1128.         suffix = pPrinterPB->driverOutName + pPrinterPB->driverOutName[0] - 2;
  1129.         infix = pPrinterPB->driverOutName + kDrvrFirstDigit;
  1130.         infix[0] = HiHex( -pPrinterPB->outRefNum -1 );
  1131.         infix[1] = LoHex( -pPrinterPB->outRefNum -1 );
  1132.         suffix[0] = 'O';
  1133.         suffix[1] = 'u';
  1134.         suffix[2] = 't';
  1135.         TradRenameDriver( pPrinterPB->outRefNum, pPrinterPB->driverOutName );
  1136.         //
  1137.         //    set the driver data to point to our parameter block
  1138.         //
  1139.         err = OpenDriver( pPrinterPB->driverOutName, &refNum );
  1140.         if ( err == noErr )
  1141.         {
  1142.             struct usbPrinterPBStruct *param = pPrinterPB;
  1143.             err = Control( refNum, kDrvrPrivateSetStorage, ¶m );
  1144.             CloseDriver( refNum );
  1145.         }
  1146.         err = TradInstallDriverFromHandle( pPrinterPB->hDrvr, kMinDrvrUnitNumber, TradHighestUnitNumber() + 1, &pPrinterPB->inRefNum );
  1147.         if ( err == noErr )
  1148.         {
  1149.             
  1150.             suffix = pPrinterPB->driverInName + pPrinterPB->driverInName[0] - 1;
  1151.             infix = pPrinterPB->driverInName + kDrvrFirstDigit;
  1152.             infix[0] = HiHex( -pPrinterPB->inRefNum -1 );
  1153.             infix[1] = LoHex( -pPrinterPB->inRefNum -1 );
  1154.             suffix[0] = 'I';
  1155.             suffix[1] = 'n';
  1156.             TradRenameDriver( pPrinterPB->inRefNum, pPrinterPB->driverInName );
  1157.             //
  1158.             //    set the driver data to point to our parameter block
  1159.             //
  1160.             err = OpenDriver( pPrinterPB->driverInName, &refNum );
  1161.             if ( err == noErr )
  1162.             {
  1163.                 struct usbPrinterPBStruct *param = pPrinterPB;
  1164.                 err = Control( refNum, kDrvrPrivateSetStorage, ¶m );
  1165.                 CloseDriver( refNum );
  1166.             }
  1167.         }
  1168.     }
  1169.     
  1170.     return err;
  1171. }
  1172.  
  1173. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1174.     Name:        GetCapability
  1175.  
  1176.     Input Parameters:    
  1177.         
  1178.     Output Parameters:
  1179.         
  1180.     Description:
  1181.         Asynchronous completion.
  1182.  
  1183.  
  1184.  
  1185. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1186. static void
  1187. GetCapability( struct usbPrinterPBStruct *pPrinterPB, unsigned char *p, int length )
  1188. {
  1189.     //
  1190.     //    queue a transaction to retrieve the 1284 capability string
  1191.     //        we must have assigned the interface by this point since the capability string
  1192.     //        may vary with the interface
  1193.     //
  1194.     OSStatus        err;
  1195.     USBPB            *pb = &pPrinterPB->pb;
  1196.  
  1197.     SetNullUSBParamBlock( pPrinterPB->deviceRef, &pPrinterPB->pb );
  1198.     
  1199.     pb->usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBIn, kUSBClass, kUSBInterface);
  1200.     pb->usbBuffer = 0;
  1201.     pb->usbActCount = 0;
  1202.     pb->usbReqCount = 0;
  1203.  
  1204.     pb->usb.cntl.BRequest = kUSBPrintClassGetDeviceID;
  1205.     pb->usb.cntl.WValue = 0;            // configuration
  1206.     pb->usb.cntl.WIndex = (pPrinterPB->interfaceNumber<<8) | pPrinterPB->alternateSetting;
  1207.  
  1208.     pb->usbReqCount = length;
  1209.     pb->usbBuffer = p;
  1210.  
  1211.     pb->usbRefcon |= kTransactionPending;
  1212.     pb->usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  1213.     err = USBDeviceRequest(pb);
  1214.     if(immediateError(err))
  1215.     {
  1216.         USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "GetCapability", 0);
  1217.         pb->usbRefcon |= kReturnFromDriver;
  1218.     }
  1219. }
  1220.  
  1221. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1222.     Name:        IsLucentCable
  1223.  
  1224.     Input Parameters:    
  1225.         dev            USB device descriptor
  1226.         
  1227.     Output Parameters:
  1228.         Return 1 if the USB device is a USB-parallel cable
  1229.         
  1230.     Description:
  1231.         
  1232.  
  1233.  
  1234.  
  1235. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1236. static int
  1237. IsLucentCable( USBDeviceDescriptor    *dev )
  1238. {
  1239.     return ( USBToHostWord(dev->vendor) == 0x47E && USBToHostWord(dev->product) == 0x1001 )? 1: 0;
  1240. }
  1241.  
  1242.  
  1243. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1244.     Name:        GetInterface
  1245.  
  1246.     Input Parameters:    
  1247.         
  1248.     Output Parameters:
  1249.         
  1250.     Description:
  1251.         Asynchronous completion.
  1252.  
  1253.  
  1254.  
  1255. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1256. static void
  1257. GetInterface( USBPB *pb, UInt8 *alt )
  1258. {
  1259.     //
  1260.     //    make sure we account for any alternate interface currently in use by the device
  1261.     //
  1262.     OSStatus    err;
  1263.  
  1264.     pb->usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBIn, kUSBStandard, kUSBInterface);
  1265.  
  1266.     pb->usb.cntl.BRequest = kUSBRqGetInterface;
  1267.     pb->usb.cntl.WValue = 0; 
  1268.     pb->usb.cntl.WIndex = 0;
  1269.  
  1270.     pb->usbReqCount = sizeof(UInt8);        // single byte is requested
  1271.     pb->usbBuffer = alt;
  1272.  
  1273.     pb->usbStatus = 0;
  1274.     pb->usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  1275.     pb->usbRefcon |= kTransactionPending;
  1276.  
  1277.     err = USBDeviceRequest(pb);
  1278.     if(immediateError(err))
  1279.     {
  1280.         USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "GetInterface", 0);
  1281.         pb->usbRefcon |= kReturnFromDriver;
  1282.     }
  1283. }
  1284.  
  1285.  
  1286. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1287.     Name:        ReadCompletion
  1288.  
  1289.     Input Parameters:    
  1290.         pb                        USB parameter block
  1291.         
  1292.     Output Parameters:
  1293.         <none>
  1294.  
  1295.     Description:
  1296.         USB read requests complete here.
  1297.         We dequeue the MacOS DRVR read requests
  1298.  
  1299.  
  1300.  
  1301.  
  1302.  
  1303.  
  1304.  
  1305.  
  1306. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1307. static void
  1308. ReadCompletion(USBPB *pb)
  1309. {
  1310.     //    call the user completion routine
  1311.     struct usbPrinterPBStruct
  1312.             *pPrinterPB =  (struct usbPrinterPBStruct    *) pb->usbRefcon;
  1313.     IOParamPtr     clientParam = pPrinterPB->readDrvr.pb;
  1314.     OSStatus        err = pb->usbStatus;
  1315.     DCtlPtr            ctlLocal;
  1316.  
  1317. #if MACSBUG_ON_READ_COMPLETE
  1318.     Str255    text;
  1319.     sprintf( (char *)text, " PrinterClass Read Complete(%d): %d", pb->usbStatus, pb->usbActCount );
  1320.     text[0] = CStrLen((char *)text); // c2pstr
  1321.     DebugStr( text );
  1322. #endif
  1323.  
  1324. #if DOUBLE_BUFFER
  1325.     //
  1326.     //    copy the user data from our page aligned buffer
  1327.     //
  1328.     USBExpertStatusLevel(5, pb->usbReference, "\p" kStrPrinterClass "ReadCompletion - bytes read  " , (UInt32)pb->usbActCount );
  1329.  
  1330.     if ( pb->usbActCount > 0 )
  1331.         BlockCopy( pPrinterPB->pageReadAlignedBuffer, clientParam->ioBuffer + clientParam->ioActCount, pb->usbActCount );
  1332. #endif
  1333.     //    update the amount of data actually transferred
  1334.     clientParam->ioActCount += pb->usbActCount;
  1335.  
  1336.     switch( pb->usbStatus )
  1337.     {
  1338.         //
  1339.         //    only retry low level hardware problems
  1340.         //        note: abort transactions will end up here as well
  1341.         //
  1342.     case kUSBLinkErr:
  1343.     case kUSBCRCErr:                                /*  Pipe stall, bad CRC */
  1344.     case kUSBBitstufErr:                            /*  Pipe stall, bitstuffing */
  1345.     case kUSBDataToggleErr:                        /*  Pipe stall, Bad data toggle */
  1346.     case kUSBNotRespondingErr:                    /*  Pipe stall, No device, device hung */
  1347.     case kUSBPIDCheckErr:                        /*  Pipe stall, PID CRC error */
  1348.     case kUSBWrongPIDErr:                        /*  Pipe stall, Bad or wrong PID */
  1349.         if (  --(pPrinterPB->readRetryCount) > 0 ) 
  1350.         {
  1351.             // we got an error, and we still want to retry, clear any stalls
  1352.             USBExpertStatusLevel(5, pb->usbReference, "\p" kStrPrinterClass "ReadCompletion retry" , pb->usbStatus );
  1353.             USBClearPipeStallByReference(pPrinterPB->readPipeRef);
  1354.             pb->usbStatus = noErr;
  1355.         }
  1356.         break;
  1357.     case kUSBAbortedError:                        /* user cancel, or hot unplug */
  1358.         USBClearPipeStallByReference(pPrinterPB->readPipeRef);
  1359.         USBClearPipeStallByReference(pPrinterPB->deviceRef);
  1360.         break;
  1361.         //
  1362.         //    any other error will be reported to the client
  1363.         //
  1364.     default:
  1365.     case noErr:
  1366.         break;
  1367.     }
  1368.     if ( pb->usbStatus == noErr &&                                     // there were no problems
  1369.         pb->usbActCount >= pb->usbReqCount &&                        // we got all the data we requested
  1370.         clientParam->ioActCount < clientParam->ioReqCount )    // we still want more data
  1371.     {
  1372.         //
  1373.         //    haven't finish the client's request
  1374.         //        update the pointers and start another bulk read transaction
  1375.         //
  1376. #if LOCK_MEMORY
  1377.         err = UnlockMemory( pb->usbBuffer, pb->usbReqCount );
  1378.         IF_DEBUG( if ( err != noErr ) DebugStr( "\pPrinterClass ReadCompletion UnlockMem failed" ) );
  1379. #endif
  1380.         pb->usbBuffer = clientParam->ioBuffer + clientParam->ioActCount;
  1381.         pb->usbReqCount = clientParam->ioReqCount - clientParam->ioActCount;
  1382. #if MAX_USB_TRANSFER_SIZE
  1383.         if ( pb->usbReqCount > MAX_USB_TRANSFER_SIZE )
  1384.             pb->usbReqCount = MAX_USB_TRANSFER_SIZE;
  1385. #endif
  1386. #if DOUBLE_BUFFER
  1387.         //
  1388.         //    make sure we have enough room in our buffer
  1389.         //
  1390.         if ( pb->usbReqCount > pPrinterPB->pageReadAlignedBufferSize )
  1391.             pb->usbReqCount = pPrinterPB->pageReadAlignedBufferSize;
  1392.         pb->usbBuffer = pPrinterPB->pageReadAlignedBuffer;
  1393. #endif
  1394. #if LOCK_MEMORY
  1395.         err = LockMemory( pb->usbBuffer, pb->usbReqCount );
  1396.         IF_DEBUG( if ( err != noErr ) DebugStr( "\pPrinterClass ReadCompletion LockMem failed" ) );
  1397.         if ( err == noErr )
  1398. #endif
  1399.         err = SafeUSBBulkRead( pb );
  1400.         if ( immediateError(err) )
  1401.         {
  1402.             USBExpertStatusLevel(5, pb->usbReference, "\p" kStrPrinterClass "ReadCompletion finish immed err" , err );
  1403.  
  1404.             pb->usbCompletion = (USBCompletion) NULL;    // checked by Finalize
  1405.             if ( pPrinterPB->readDrvr.ctl != NULL )
  1406.             {
  1407.                 ctlLocal = pPrinterPB->readDrvr.ctl;
  1408.                 pPrinterPB->readDrvr.ctl = NULL;
  1409.                 CallUniversalProc( LMGetJIODone(), uppIODoneProcInfo, err, clientParam, ctlLocal ); 
  1410.             }
  1411.         }
  1412.     }
  1413.     else
  1414.     {
  1415.         //
  1416.         //        either we have an error which we're not retrying
  1417.         //            or we successfully completed
  1418.         //
  1419. #if LOCK_MEMORY
  1420.         err = UnlockMemory( pb->usbBuffer, pb->usbReqCount );
  1421.         IF_DEBUG( if ( err != noErr ) DebugStr( "\pPrinterClass ReadCompletion concluded UnlockMem failed" ) );
  1422. #endif
  1423.         IF_DEBUG( if (pb->usbStatus != noErr) USBExpertStatus(pb->usbReference, "\p" kStrPrinterClass "ReadCompletion Error" , pb->usbStatus ) );
  1424.         pb->usbCompletion = (USBCompletion) NULL;    // checked by Finalize
  1425.         USBExpertStatusLevel(5, pb->usbReference, "\p" kStrPrinterClass "readDrvr.ctl = " , (UInt32)pPrinterPB->readDrvr.ctl );
  1426.         if ( pPrinterPB->readDrvr.ctl != NULL )
  1427.         {
  1428.             ctlLocal = pPrinterPB->readDrvr.ctl;
  1429.             pPrinterPB->readDrvr.ctl = NULL;
  1430.             CallUniversalProc( LMGetJIODone(), uppIODoneProcInfo, pb->usbStatus, clientParam, ctlLocal); 
  1431.         }
  1432.         else
  1433.         {
  1434.             IF_DEBUG( DebugStr( "\pReadCompletion() pPrinterPB->readDrvr.ctl == NULL" ) );
  1435.         }
  1436.     }
  1437. }
  1438.  
  1439.  
  1440. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1441.     Name:        WriteCompletion
  1442.  
  1443.     Input Parameters:    
  1444.         pb                        USB parameter block
  1445.         
  1446.     Output Parameters:
  1447.         <none>
  1448.  
  1449.     Description:
  1450.         USB write requests complete here.
  1451.         We dequeue the MacOS DRVR write requests
  1452.  
  1453.         when breaking up transactions we use ioActCount to determine how much remains 
  1454.                 of the original request and where the next request begins
  1455.         if we've failed with a USB error
  1456.             usbActCount indicates how much data has been transferred with the current request
  1457.             and if the retry count hasn't been exceeded
  1458.                 we proceed as if we'd just requested that much in this transactions
  1459.         note the retry count is cumulative for the original client request
  1460.             not for each usb transaction
  1461.  
  1462.  
  1463.  
  1464.  
  1465.  
  1466.  
  1467.  
  1468.  
  1469.  
  1470.  
  1471. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1472. static void
  1473. WriteCompletion(USBPB *pb)
  1474. {
  1475.     //    call the user completion routine
  1476.     struct usbPrinterPBStruct
  1477.                     *pPrinterPB =  (struct usbPrinterPBStruct    *) pb->usbRefcon;
  1478.     IOParamPtr     clientParam = pPrinterPB->writeDrvr.pb;
  1479.     DCtlPtr            ctlLocal;
  1480.     OSStatus        err = pb->usbStatus;
  1481.  
  1482. #if MACSBUG_ON_WRITE_COMPLETE
  1483.     Str255    text;
  1484.     sprintf( (char *)text, " PrinterClass Write Complete(%d): %d", pb->usbStatus, pb->usbActCount );
  1485.     text[0] = CStrLen((char *)text); // c2pstr
  1486.     DebugStr( text );
  1487. #endif
  1488.  
  1489.     //    update the amount of data actually transferred
  1490.     clientParam->ioActCount += pb->usbActCount;
  1491.     USBExpertStatusLevel(5, pb->usbReference, "\p" kStrPrinterClass "WriteCompletion - bytes written  " , (UInt32)pb->usbActCount);
  1492.  
  1493.     switch( pb->usbStatus )
  1494.     {
  1495.         //
  1496.         //    only retry low level hardware problems
  1497.         //        note: abort transactions will end up here as well
  1498.         //
  1499.     case kUSBLinkErr:
  1500.     case kUSBCRCErr:                                /*  Pipe stall, bad CRC */
  1501.     case kUSBBitstufErr:                            /*  Pipe stall, bitstuffing */
  1502.     case kUSBDataToggleErr:                        /*  Pipe stall, Bad data toggle */
  1503.     case kUSBNotRespondingErr:                    /*  Pipe stall, No device, device hung */
  1504.     case kUSBPIDCheckErr:                        /*  Pipe stall, PID CRC error */
  1505.     case kUSBWrongPIDErr:                        /*  Pipe stall, Bad or wrong PID */
  1506.         if (  --(pPrinterPB->writeRetryCount) > 0 ) 
  1507.         {
  1508.             // we got an error, and we still want to retry, clear any stalls
  1509.             USBExpertStatus(pb->usbReference, "\p" kStrPrinterClass "WriteCompletion retry" , pb->usbStatus );
  1510.             USBClearPipeStallByReference(pPrinterPB->writePipeRef);
  1511.             pb->usbStatus = noErr;
  1512.         }
  1513.         break;
  1514.     case kUSBAbortedError:                        /* user cancel, or hot unplug */
  1515.         USBClearPipeStallByReference(pPrinterPB->writePipeRef);
  1516.         USBClearPipeStallByReference(pPrinterPB->deviceRef);
  1517.         break;
  1518.         //
  1519.         //    any other error will be reported to the client
  1520.         //
  1521.     default:
  1522.     case noErr:
  1523.         break;
  1524.     }
  1525.  
  1526.     if ( pb->usbStatus == noErr && clientParam->ioActCount < clientParam->ioReqCount )
  1527.     {
  1528.         //
  1529.         //    haven't finish the client's request
  1530.         //        update the pointers and start another bulkOut transaction
  1531.         //
  1532. #if LOCK_MEMORY
  1533.         err = UnlockMemory( pb->usbBuffer, pb->usbReqCount );
  1534.         IF_DEBUG( if ( err != noErr ) DebugStr( "\pPrinterClass WriteCompletion UnlockMem failed" ) );
  1535. #endif
  1536.         pb->usbBuffer = clientParam->ioBuffer + clientParam->ioActCount;
  1537.         pb->usbReqCount = clientParam->ioReqCount - clientParam->ioActCount;
  1538. #if MAX_USB_TRANSFER_SIZE
  1539.         if ( pb->usbReqCount > MAX_USB_TRANSFER_SIZE )
  1540.             pb->usbReqCount = MAX_USB_TRANSFER_SIZE;
  1541. #endif
  1542. #if DOUBLE_BUFFER
  1543.         //
  1544.         //    make sure we have enough room in our buffer
  1545.         //    then copy the user data into our page aligned buffer
  1546.         //
  1547.         if ( pb->usbReqCount > pPrinterPB->pageWriteAlignedBufferSize )
  1548.             pb->usbReqCount = pPrinterPB->pageWriteAlignedBufferSize;
  1549.         BlockCopy( pb->usbBuffer, pPrinterPB->pageWriteAlignedBuffer, pb->usbReqCount );
  1550.         pb->usbBuffer = pPrinterPB->pageWriteAlignedBuffer;
  1551. #endif
  1552. #if LOCK_MEMORY
  1553.         err = LockMemory( pb->usbBuffer, pb->usbReqCount );
  1554.         IF_DEBUG( if ( err != noErr ) DebugStr( "\pPrinterClass WriteCompletion LockMem failed" ) );
  1555.         if ( err == noErr )
  1556. #endif
  1557.             err = SafeUSBBulkWrite( pb );
  1558.         if ( immediateError(err) )
  1559.         {
  1560.             USBExpertStatus(pb->usbReference, "\p" kStrPrinterClass "WriteCompletion finish immed err" , err );
  1561.  
  1562.             pb->usbCompletion = (USBCompletion) NULL;    // checked by Finalize
  1563.             if ( pPrinterPB->writeDrvr.ctl != NULL )
  1564.             {
  1565.                 ctlLocal = pPrinterPB->writeDrvr.ctl;
  1566.                 pPrinterPB->writeDrvr.ctl = NULL;
  1567.                 CallUniversalProc( LMGetJIODone(), uppIODoneProcInfo, err, clientParam, ctlLocal ); 
  1568.             }
  1569.         }
  1570.     }
  1571.     else
  1572.     {
  1573.         //
  1574.         //        either we have an error which we're not retrying
  1575.         //            or we successfully completed
  1576.         //
  1577. #if LOCK_MEMORY
  1578.         err = UnlockMemory( pb->usbBuffer, pb->usbReqCount );
  1579.         IF_DEBUG( if ( err != noErr ) DebugStr( "\pPrinterClass WriteCompletion concluded UnlockMem failed" ) );
  1580. #endif
  1581.         IF_DEBUG( if (pb->usbStatus != noErr) USBExpertStatus(pb->usbReference, "\p" kStrPrinterClass "WriteCompletion Error" , pb->usbStatus ) );
  1582.         pb->usbCompletion = (USBCompletion) NULL;    // checked by Finalize
  1583.         USBExpertStatusLevel(5, pb->usbReference, "\p" kStrPrinterClass "writeDrvr.ctl = " , (UInt32)pPrinterPB->writeDrvr.ctl );
  1584.         if ( pPrinterPB->writeDrvr.ctl != NULL )
  1585.         {
  1586.             ctlLocal = pPrinterPB->writeDrvr.ctl;
  1587.             pPrinterPB->writeDrvr.ctl = NULL;
  1588.             CallUniversalProc( LMGetJIODone(), uppIODoneProcInfo, pb->usbStatus, clientParam, ctlLocal ); 
  1589.         }
  1590.         else
  1591.         {
  1592.             IF_DEBUG( DebugStr( "\pWriteCompletion() pPrinterPB->writeDrvr.ctl == NULL" ) );
  1593.         }
  1594.     }
  1595. }
  1596.  
  1597. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1598.     Name:        QueueRead
  1599.  
  1600.     Input Parameters:    
  1601.         pb                        MacOS device manager parameter block
  1602.         ctl                    device manager dCtl block
  1603.         pPrinterPB            current printing device class's storage
  1604.         
  1605.     Output Parameters:
  1606.         <none>
  1607.  
  1608.     Description:
  1609.         MacOS DRVR read requests are re-queued here to the USB
  1610.         Since we only allow one read request pending at a time, we're able
  1611.         to use the USB refCon to point to our class driver's storage.
  1612.  
  1613.  
  1614.  
  1615.  
  1616. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1617. void
  1618. QueueRead( IOParamPtr pb, DCtlPtr ctl, struct usbPrinterPBStruct *pPrinterPB )
  1619. {    
  1620.     OSStatus    err;
  1621.     USBPB        *usbprint = &pPrinterPB->in;
  1622.     
  1623. #if MACSBUG_ON_READ
  1624.     Str255    text;
  1625.  
  1626.     sprintf( (char *)text, " PrinterClass Read: %d @ %08x", pb->ioReqCount, pb->ioBuffer );
  1627.     text[0] = CStrLen((char *)text); // c2pstr
  1628.     USBExpertStatusLevel(5, usbprint->usbReference, text, usbprint->usbStatus );
  1629.     DebugStr( text );
  1630. #endif
  1631.  
  1632.     pb->ioActCount = 0;        // nothing transfered yet
  1633.     if ( pPrinterPB->terminating )
  1634.         pb->ioResult = abortErr;
  1635.     else
  1636.     {
  1637.  
  1638.         pPrinterPB->readRetryCount = 5;
  1639.         pPrinterPB->readDrvr.pb= pb;
  1640.         pPrinterPB->readDrvr.ctl = ctl;
  1641.         if (( pPrinterPB->readPipeRef != NULL ) && (pPrinterPB->printerConfigured))
  1642.         {
  1643.             SetNullUSBParamBlock( pPrinterPB->readPipeRef,  usbprint );
  1644.             USBExpertStatusLevel(5, usbprint->usbReference, "\pSet up to do bulk read", pb->ioReqCount );
  1645.             usbprint->usbActCount = 0;
  1646.             usbprint->usbBuffer = pb->ioBuffer;
  1647.             usbprint->usbReqCount = pb->ioReqCount;
  1648.  
  1649. #if MAX_USB_TRANSFER_SIZE
  1650.             //
  1651.             //    the completion routine will queue another BulkWrite until we exhaust the data
  1652.             //        or there is an error which can't be retried
  1653.             //
  1654.             if ( usbprint->usbReqCount > MAX_USB_TRANSFER_SIZE )
  1655.                 usbprint->usbReqCount = MAX_USB_TRANSFER_SIZE;
  1656. #endif
  1657. #if DOUBLE_BUFFER
  1658.             //
  1659.             //    make sure we have enough room in our buffer
  1660.             //    then copy the user data into our page aligned buffer
  1661.             //
  1662.             if ( usbprint->usbReqCount > pPrinterPB->pageReadAlignedBufferSize )
  1663.                 usbprint->usbReqCount = pPrinterPB->pageReadAlignedBufferSize;
  1664.             usbprint->usbBuffer = pPrinterPB->pageReadAlignedBuffer;
  1665. #endif
  1666.             usbprint->usbRefcon = (unsigned long) pPrinterPB;
  1667.             usbprint->usbCompletion = (USBCompletion) ReadCompletion;
  1668.             
  1669.             pb->ioResult = ioInProgress;
  1670. #if LOCK_MEMORY
  1671.             err = LockMemory( usbprint->usbBuffer, usbprint->usbReqCount );
  1672.             IF_DEBUG( if ( err != noErr ) DebugStr( "\pPrinterClass QueueRead LockMem failed" ) );
  1673.             if ( err == noErr )
  1674. #endif
  1675.             err = SafeUSBBulkRead( usbprint );
  1676.             if ( immediateError(err) )
  1677.             {
  1678.                 USBExpertStatus(usbprint->usbReference, "\pError doing bulk read",0 );
  1679.                 IF_DEBUG( DebugStr( USBStatusStr(err, kPString) ) );
  1680.                 pb->ioResult = err;
  1681.             }
  1682.         }
  1683.         else
  1684.         {
  1685.             USBExpertStatus(usbprint->usbReference, "\p" kStrPrinterClass "Read to unopened pipe" , usbprint->usbStatus ) ;
  1686.             pb->ioResult = abortErr;
  1687.         }
  1688.     }
  1689. }
  1690.  
  1691. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1692.     Name:        QueueWrite
  1693.  
  1694.     Input Parameters:    
  1695.         pb                        MacOS device manager parameter block
  1696.         ctl                    device manager dCtl block
  1697.         pPrinterPB            current printing device class's storage
  1698.         
  1699.     Output Parameters:
  1700.         <none>
  1701.  
  1702.     Description:
  1703.         MacOS DRVR write requests are re-queued here to the USB
  1704.         Since we only allow one read request pending at a time, we're able
  1705.         to use the USB refCon to point to our class driver's storage.
  1706.  
  1707.  
  1708.  
  1709. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1710. void
  1711. QueueWrite( IOParamPtr pb, DCtlPtr ctl, struct usbPrinterPBStruct *pPrinterPB )
  1712. {
  1713.     OSStatus    err;
  1714.     USBPB        *usbprint = &pPrinterPB->out;
  1715. #if VIRTUAL_MEMORY_CHECK
  1716.     //
  1717.     //    dump the VM table
  1718.     //
  1719.     Str255                        text;
  1720.     LogicalToPhysicalTable    *vmTable;
  1721.     MemoryBlock                    *physical;
  1722.     unsigned long                vmCount,
  1723.                                     vmEntry,
  1724.                                     vmTblLength;
  1725. #endif
  1726.  
  1727. #if MACSBUG_ON_WRITE
  1728.     Str255    text;
  1729.     sprintf( (char *)text, " PrinterClass Write: %d @ %08x", pb->ioReqCount, pb->ioBuffer );
  1730.     text[0] = CStrLen((char *)text); // c2pstr
  1731.     USBExpertStatusLevel(5, usbprint->usbReference, text, usbprint->usbStatus );
  1732.     DebugStr( text );
  1733. #endif
  1734.  
  1735. #if VIRTUAL_MEMORY_CHECK
  1736.     //
  1737.     //    this check current won't compile without runtime error: need to lock memory, but lock has moved
  1738.     //
  1739.     sprintf( (char *)text, " PrinterClass Write: %d @ %08x", pb->ioReqCount, pb->ioBuffer );
  1740.     text[0] = CStrLen((char *)text); // c2pstr
  1741.     USBExpertStatusLevel(5, usbprint->usbReference, text, usbprint->usbStatus );
  1742.     
  1743.     vmCount = 127;
  1744.     vmTblLength = (vmCount+1)*sizeof(MemoryBlock);
  1745.     vmTable = (LogicalToPhysicalTable *) NewPtrSys( vmTblLength );
  1746.     LockMemory( vmTable, vmTblLength );
  1747.     LockMemory( &vmCount, sizeof(unsigned long) );
  1748.     vmTable->logical.address = pb->ioBuffer;
  1749.     vmTable->logical.count = pb->ioReqCount;
  1750.     err = GetPhysical( vmTable, &vmCount );
  1751.     
  1752.     if ( err == noErr )
  1753.     {
  1754.         for ( vmEntry = 0, physical = &vmTable->physical[0]; vmEntry < vmCount; ++vmEntry , ++physical)
  1755.         {
  1756.             sprintf( (char *)text, " PrinterClass Write: VM @%08x (%d)", physical->address, physical->count );
  1757.             text[0] = CStrLen((char *)text); // c2pstr
  1758.             USBExpertStatusLevel(5, usbprint->usbReference, text, usbprint->usbStatus );
  1759.         }
  1760.     }
  1761.     UnlockMemory( vmTable, vmTblLength );
  1762.     UnlockMemory( &vmCount, sizeof(unsigned long) );
  1763. #endif
  1764.     pb->ioActCount = 0;        // nothing transfered yet
  1765.  
  1766.  
  1767.     usbprint->usbStatus = noErr;    // forget about abort and things from previous writes
  1768.     if ( pPrinterPB->terminating )
  1769.         pb->ioResult = abortErr;
  1770.     else
  1771.     {
  1772.         pPrinterPB->writeRetryCount = 5;
  1773.         pPrinterPB->writeDrvr.pb = pb;
  1774.         pPrinterPB->writeDrvr.ctl = ctl;
  1775.         if (( pPrinterPB->writePipeRef != NULL ) && (pPrinterPB->printerConfigured))
  1776.         {
  1777.             SetNullUSBParamBlock( pPrinterPB->writePipeRef,  usbprint );
  1778.             USBExpertStatusLevel(5, usbprint->usbReference, "\pSet up to do bulk write", pb->ioReqCount );
  1779.             usbprint->usbActCount = 0;
  1780.             usbprint->usbBuffer = pb->ioBuffer;
  1781.             usbprint->usbReqCount = pb->ioReqCount;
  1782. #if MAX_USB_TRANSFER_SIZE
  1783.             //
  1784.             //    the completion routine will queue another BulkWrite until we exhaust the data
  1785.             //        or there is an error which can't be retried
  1786.             //
  1787.             if ( usbprint->usbReqCount > MAX_USB_TRANSFER_SIZE )
  1788.                 usbprint->usbReqCount = MAX_USB_TRANSFER_SIZE;
  1789. #endif
  1790. #if DOUBLE_BUFFER
  1791.             //
  1792.             //    make sure we have enough room in our buffer
  1793.             //    then copy the user data into our page aligned buffer
  1794.             //
  1795.             if ( usbprint->usbReqCount > pPrinterPB->pageWriteAlignedBufferSize )
  1796.                 usbprint->usbReqCount = pPrinterPB->pageWriteAlignedBufferSize;
  1797.             BlockCopy( usbprint->usbBuffer, pPrinterPB->pageWriteAlignedBuffer, usbprint->usbReqCount );
  1798.             usbprint->usbBuffer = pPrinterPB->pageWriteAlignedBuffer;
  1799. #endif
  1800.             usbprint->usbRefcon = (unsigned long) pPrinterPB;
  1801.             usbprint->usbCompletion = (USBCompletion) WriteCompletion;
  1802.              
  1803.             pb->ioResult = ioInProgress;
  1804.     
  1805. #if LOCK_MEMORY
  1806.             err = LockMemory( usbprint->usbBuffer, usbprint->usbReqCount );
  1807.             IF_DEBUG( if ( err != noErr ) DebugStr( "\pPrinterClass QueueWrite LockMem failed" ) );
  1808.             if ( err == noErr )
  1809. #endif
  1810.                 err = SafeUSBBulkWrite( usbprint );
  1811.             if ( immediateError(err) )
  1812.             {
  1813.                 USBExpertStatus(usbprint->usbReference, "\pError doing bulk write",0 );
  1814.                 IF_DEBUG( DebugStr( USBStatusStr(err, kPString) ) );
  1815.                 pb->ioResult = err;
  1816.             }
  1817.             //
  1818.             //    note our logging is one write for each the client request
  1819.             //        not one write for each usb transaction
  1820.             //
  1821.             LOGGING( fwrite( pb->ioBuffer, sizeof(char), pb->ioReqCount, logfile ) );
  1822.         }
  1823.         else
  1824.         {
  1825.             USBExpertStatus(usbprint->usbReference, "\p" kStrPrinterClass "Write to unopened pipe" , usbprint->usbStatus );
  1826.             pb->ioResult = abortErr;
  1827.         }
  1828.     }
  1829. }
  1830.  
  1831.  
  1832. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1833.     Name:        Abort
  1834.  
  1835.     Input Parameters:    
  1836.         refNum            DRVR refnum
  1837.         pPrinterPB        current printing device class's storage
  1838.  
  1839.     Output Parameters:
  1840.         
  1841.     Description:
  1842.         Asynchronous completion.
  1843.         Note: USBAbortPipeByReference can leave the data toggle in the wrong state.
  1844.                 We need to abort both pipes, and then the client must soft reset the printer
  1845.                 to get the printer's data toggles correct.
  1846.         We prematurely call completion routines for active i/o so that CloseDriverSync
  1847.             will not hang the system after an abort, including hot unplug. This works out okay,
  1848.             since the request will be dequeued now, and when the i/o actually terminates
  1849.             the system will be called with an invalid queue element and then reject this second
  1850.             attempt to dequeue the i/o.
  1851.  
  1852.  
  1853.  
  1854.  
  1855. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1856. OSStatus
  1857. Abort( DriverRefNum refNum, struct usbPrinterPBStruct *pPrinterPB )
  1858. {
  1859.     OSStatus        err = noErr;
  1860.  
  1861.  
  1862.     refNum = 0;    // unused
  1863.     //
  1864.     //    if there's any pending io this will call the completion routine
  1865.     //
  1866.     err = USBAbortPipeByReference( pPrinterPB->writePipeRef );
  1867.     err = USBAbortPipeByReference( pPrinterPB->readPipeRef );
  1868.  
  1869.     if ( pPrinterPB->out.usbCompletion != (USBCompletion) NULL )
  1870.         CallUniversalProc( LMGetJIODone(), uppIODoneProcInfo, abortErr, pPrinterPB->writeDrvr.pb, pPrinterPB->writeDrvr.ctl ); 
  1871.     if ( pPrinterPB->in.usbCompletion != (USBCompletion) NULL )
  1872.         CallUniversalProc( LMGetJIODone(), uppIODoneProcInfo, abortErr, pPrinterPB->readDrvr.pb, pPrinterPB->readDrvr.ctl ); 
  1873.     return err;
  1874. }
  1875.  
  1876.  
  1877. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1878.     Name:        CompletionProc
  1879.  
  1880.     Input Parameters:    
  1881.         pb                    USB param block ptr
  1882.     
  1883.     Output Parameters:
  1884.         
  1885.     Description:
  1886.         Asynchronous completion routine for DRVR requests.
  1887.  
  1888.  
  1889.  
  1890.  
  1891.  
  1892. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1893. static void 
  1894. CompletionProc(USBPB *pb)
  1895. {
  1896.     //    call the user completion routine
  1897.     struct usbPrinterPBStruct
  1898.                     *pPrinterPB = (struct usbPrinterPBStruct    *) pb->usbRefcon;
  1899.     IOParamPtr     clientParam = pPrinterPB->statusDrvr.pb;
  1900.  
  1901.     clientParam->ioActCount = pb->usbActCount;
  1902.  
  1903.     if ( pb->usbStatus != noErr ) 
  1904.     {
  1905.         USBClearPipeStallByReference(pb->usbReference);  // we got an error, try to clear any stalls
  1906.  
  1907.         IF_DEBUG( USBExpertStatus(pPrinterPB->deviceRef, "\p" kStrPrinterClass "CompletionProc Error" , pb->usbStatus ) );
  1908.         IF_DEBUG( USBExpertStatus(pPrinterPB->deviceRef, USBStatusStr(pb->usbStatus, kPString) , pb->usbStatus ) );
  1909.     }
  1910.  
  1911.     pb->usbCompletion = (USBCompletion) NULL;    // checked by Finalize
  1912.     if ( pPrinterPB->statusDrvr.ctl != NULL )
  1913.         CallUniversalProc( LMGetJIODone(), uppIODoneProcInfo, pb->usbStatus, clientParam, pPrinterPB->statusDrvr.ctl ); 
  1914. }
  1915.  
  1916. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1917.     Name:        CentronicsStatus
  1918.  
  1919.     Input Parameters:    
  1920.         pb                        MacOS device manager parameter block
  1921.         ctl                    device manager dCtl block
  1922.         pPrinterPB            current printing device class's storage
  1923.  
  1924.     Output Parameters:
  1925.         pStatusByte        
  1926.         
  1927.     Description:
  1928.         setup the device request for a USB printer class request one byte status.
  1929.  
  1930.  
  1931.  
  1932.  
  1933.  
  1934. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1935. static void
  1936. CentronicsStatus( USBPB *usbprint, Ptr buffer, short interfaceNumber )
  1937. {
  1938.     usbprint->usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBIn, kUSBClass, kUSBInterface);
  1939.  
  1940.     usbprint->usb.cntl.BRequest = kUSBPrintClassGetCentronicsStatus;
  1941.     usbprint->usb.cntl.WValue = 0;
  1942.     usbprint->usb.cntl.WIndex = interfaceNumber;
  1943.  
  1944.     usbprint->usbReqCount = 1;
  1945.     usbprint->usbBuffer = buffer;
  1946. }
  1947.  
  1948. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1949.     Name:        SoftReset
  1950.  
  1951.     Input Parameters:    
  1952.         usbprint                USB param block
  1953.         interfaceNumber
  1954.  
  1955.     Output Parameters:
  1956.         
  1957.     Description:
  1958.         Setup the device request for a USB printer class request soft reset.
  1959.  
  1960.  
  1961.  
  1962.  
  1963.  
  1964. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1965. void
  1966. SoftReset( USBPB *usbprint, short interfaceNumber )
  1967. {
  1968.     usbprint->usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBClass, kUSBOther);
  1969.  
  1970.     usbprint->usb.cntl.BRequest = kUSBPrintClassSoftReset;
  1971.     usbprint->usb.cntl.WValue = 0;
  1972.     usbprint->usb.cntl.WIndex = interfaceNumber;
  1973.  
  1974.     usbprint->usbReqCount = 0;
  1975.     usbprint->usbBuffer = NULL;
  1976.  
  1977. }
  1978.  
  1979. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1980.     Name:        CapabilityRequest
  1981.  
  1982.     Input Parameters:    
  1983.         usbprint            USB parameter block
  1984.         p                    result pointer
  1985.         length            amount of data allocated
  1986.         config
  1987.         interfaceNum
  1988.         alternateSetting
  1989.         
  1990.  
  1991.     Output Parameters:
  1992.         p                    result pointer
  1993.         length            amount of data allocated
  1994.         
  1995.     Description:
  1996.         setup the device request for a USB printer class request 1284 id string.
  1997.  
  1998.  
  1999.  
  2000.  
  2001.  
  2002. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  2003. void
  2004. CapabilityRequest( USBPB *pb, Ptr p, long length, short configValue, short interfaceNumber, short alternateSetting  )
  2005. {
  2006.  
  2007.     pb->usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBIn, kUSBClass, kUSBInterface);
  2008.  
  2009.     pb->usb.cntl.BRequest = kUSBPrintClassGetDeviceID;
  2010.     pb->usb.cntl.WValue = configValue;        // configuration
  2011.     pb->usb.cntl.WIndex = (interfaceNumber<<8) | alternateSetting;
  2012.  
  2013.     pb->usbReqCount = length;
  2014.     pb->usbBuffer = p;
  2015.  
  2016. }
  2017.  
  2018. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2019.     Name:        StatusControlRequests
  2020.  
  2021.     Input Parameters:    
  2022.         pb                        MacOS device manager parameter block
  2023.         ctl                    device manager dCtl block
  2024.         pPrinterPB            current printing device class's storage
  2025.  
  2026.     Output Parameters:
  2027.         
  2028.     Description:
  2029.         Asynchronous completion.
  2030.  
  2031.  
  2032.  
  2033.  
  2034. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  2035.  
  2036. void
  2037. ControlStatusRequests( IOParamPtr pb, DCtlPtr ctl, struct usbPrinterPBStruct *pPrinterPB )
  2038. {
  2039.  
  2040.     //
  2041.     //    queue a transaction to retrieve the centronics status
  2042.     //
  2043.     OSStatus        err;
  2044.     USBPB            *usbprint = &pPrinterPB->pb;
  2045.     Boolean        dosomething = false;
  2046.     
  2047. #if DEBUG
  2048.     Str255        text;
  2049.  
  2050.     sprintf( (char *)text, " PrinterClass ControlStatus: %d", ((CntrlParam *) pb)->csCode );
  2051.     text[0] = CStrLen((char *)text); // c2pstr
  2052.     USBExpertStatusLevel(5, usbprint->usbReference, text, usbprint->usbStatus );
  2053. #endif
  2054.  
  2055.     if (pPrinterPB->terminating)
  2056.     {
  2057.         pb->ioResult = abortErr;
  2058.     }
  2059.     else
  2060.     {
  2061.         switch( ((CntrlParam *) pb)->csCode )
  2062.         {
  2063.         case kDrvrCentronicsStatus:
  2064.             dosomething = true;
  2065.             CentronicsStatus( usbprint,  *((Ptr *)((CntrlParam *) pb)->csParam), pPrinterPB->interfaceNumber );
  2066.             break;
  2067.         case kDrvr1284IdString:
  2068.             dosomething = true;
  2069.             CapabilityRequest( usbprint,
  2070.                                     *((Ptr *)((CntrlParam *) pb)->csParam),
  2071.                                     *((long *) &((CntrlParam *) pb)->csParam[4]),
  2072.                                     0,        // configuration
  2073.                                     pPrinterPB->interfaceNumber,
  2074.                                     pPrinterPB->alternateSetting);
  2075.             break;
  2076.         case kDrvrSoftReset:
  2077.             dosomething = true;
  2078.             SoftReset( usbprint, pPrinterPB->interfaceNumber );
  2079.             break;
  2080.         default:
  2081.             break;
  2082.         }
  2083.     
  2084.         if ( !dosomething )
  2085.         pb->ioResult = paramErr;
  2086.         else
  2087.         {
  2088.             SetNullUSBParamBlock(pPrinterPB->deviceRef,  usbprint );
  2089.             usbprint->usbActCount = 0;
  2090.             usbprint->usbCompletion = (USBCompletion)CompletionProc;
  2091.             usbprint->usbRefcon = (unsigned long) pPrinterPB;
  2092.         
  2093.             pb->ioResult = ioInProgress;
  2094.             pPrinterPB->statusDrvr.pb = pb;
  2095.             pPrinterPB->statusDrvr.ctl = ctl;
  2096.         
  2097.             err = USBDeviceRequest(usbprint);
  2098.             if(immediateError(err))
  2099.             {
  2100.                 USBExpertFatalError(usbprint->usbReference, err, "\p" kStrPrinterClass "StatusControlRequests", 0);
  2101.                 pb->ioResult = err;
  2102.             }
  2103.         }
  2104.     }
  2105. }
  2106.  
  2107.  
  2108. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2109.     Name:        PrinterDeviceCompletionProc
  2110.  
  2111.     Input Parameters:    
  2112.         pb                refCon tells which state we're completing
  2113.  
  2114.     Output Parameters:
  2115.         <none>
  2116.         
  2117.     Description:
  2118.         Complete asynch transactions initiated by PrinterDeviceInitiateTransaction.
  2119.  
  2120.  
  2121.  
  2122.  
  2123.  
  2124.  
  2125.  
  2126.  
  2127.  
  2128.  
  2129. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  2130.  
  2131. static void 
  2132. PrinterDeviceCompletionProc(USBPB *pb)
  2133. {
  2134. Str255        tempstr1,tempstr2;
  2135. register     struct usbPrinterPBStruct *pPrinterPB;
  2136. OSStatus    err;
  2137. UInt32        i = 0;
  2138.  
  2139.     
  2140.     pPrinterPB = (struct usbPrinterPBStruct *)(pb);
  2141.  
  2142.     pPrinterPB->transDepth--; 
  2143.     if ((pPrinterPB->transDepth < 0) || (pPrinterPB->transDepth > 1))
  2144.     {
  2145.         USBExpertFatalError(pPrinterPB->deviceRef, kUSBInternalErr, "\p" kStrPrinterClass "CompletionProc Illegal Transaction Depth", pPrinterPB->transDepth );
  2146.     }
  2147.  
  2148.     IF_DEBUG( USBExpertStatus(pPrinterPB->deviceRef, StateStr(pPrinterPB->pb.usbRefcon, kPString) , 1 ) );
  2149.  
  2150.     pPrinterPB->delayInProgress = false;
  2151.     
  2152.     if ( pPrinterPB->terminating )
  2153.     {
  2154.         //    if we've been hot unplugged
  2155.         //        don't startup any new transactions
  2156.         //     allow PrintDriverFinalize to continue
  2157.         pPrinterPB->pb.usbStatus = kUSBAbortedError;
  2158.         pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2159.     }
  2160.     
  2161.  
  2162.     switch( pPrinterPB->pb.usbStatus )
  2163.     {
  2164.         case kUSBPending:
  2165.         case noErr:
  2166.             pPrinterPB->pb.usbRefcon &= ~kRetryTransaction;
  2167.             pPrinterPB->retryCount = kPrinterRetryCount;
  2168.             break;
  2169.             
  2170.         case kUSBLinkErr:
  2171.         case kUSBCRCErr:                                /*  Pipe stall, bad CRC */
  2172.         case kUSBBitstufErr:                            /*  Pipe stall, bitstuffing */
  2173.         case kUSBDataToggleErr:                            /*  Pipe stall, Bad data toggle */
  2174.         case kUSBNotRespondingErr:                        /*  Pipe stall, No device, device hung */
  2175.         case kUSBPIDCheckErr:                            /*  Pipe stall, PID CRC error */
  2176.         case kUSBWrongPIDErr:                            /*  Pipe stall, Bad or wrong PID */
  2177.         
  2178.             USBClearPipeStallByReference(pPrinterPB->deviceRef);  // we got an error, try to clear any stalls
  2179.             USBExpertStatus(pPrinterPB->deviceRef, "\p" kStrPrinterClass "    retry", pPrinterPB->pb.usbStatus);
  2180.             
  2181.             // clear out the transaction pending flag
  2182.             pPrinterPB->pb.usbRefcon &= ~(kTransactionPending + kReturnFromDriver);
  2183.             pPrinterPB->pb.usbRefcon |= kRetryTransaction;
  2184.             pPrinterPB->retryCount--;
  2185.             if (!pPrinterPB->retryCount)
  2186.             {
  2187.                 USBExpertFatalError(pPrinterPB->deviceRef, kUSBInternalErr, "\p" kStrPrinterClass "Retry failed", pPrinterPB->pb.usbRefcon & ~kRetryTransaction);
  2188.                 pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2189.             } 
  2190.             else 
  2191.             {
  2192.                 pPrinterPB->pb.usbStatus = noErr;             // let's retry one more time
  2193.             }
  2194.             break;
  2195.             
  2196.         case kUSBNotFound:
  2197.             break;
  2198.             
  2199.         case kUSBAbortedError:                        /* user cancel, or hot unplug */
  2200.         default:
  2201.             // clear out the transaction pending flag
  2202.             pPrinterPB->pb.usbCompletion = (USBCompletion) NULL;
  2203.             pPrinterPB->pb.usbRefcon &= ~(kTransactionPending + kReturnFromDriver);
  2204.             pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2205.             break;
  2206.     }
  2207.  
  2208.     if (pPrinterPB->pb.usbRefcon & kTransactionPending)             
  2209.     {            
  2210.         int    length;
  2211.     
  2212.         //
  2213.         //    advance to the next state
  2214.         //
  2215.         pPrinterPB->pb.usbRefcon &= ~(kTransactionPending + kReturnFromDriver);
  2216.         switch(pPrinterPB->pb.usbRefcon)
  2217.         {
  2218.             case kFindInterface_bidirectional:
  2219.                 USBExpertStatusLevel(5, pPrinterPB->deviceRef, "\p"kStrPrinterClass"kFindInterface_bidirectional completed", pPrinterPB->pb.usb.cntl.WIndex);
  2220.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2221.                 {
  2222.                     if ((pPrinterPB->pb.usbClassType == kUSBPrintingClass) && 
  2223.                         (pPrinterPB->pb.usbSubclass == kUSBPrinterSubclass) &&
  2224.                         (pPrinterPB->pb.usbProtocol == kUSBPrinterBidirectionalProtocol))
  2225.                     {
  2226.                         USBExpertStatusLevel(5, pPrinterPB->deviceRef, "\p"kStrPrinterClass"Found bidirectional interface at alt setting ", pPrinterPB->pb.usbOther);
  2227.                         pPrinterPB->configurationNumber = pPrinterPB->pb.usb.cntl.WValue;
  2228.                         pPrinterPB->alternateSetting = pPrinterPB->pb.usbOther;
  2229.                         pPrinterPB->printerProtocol = kUSBPrinterBidirectionalProtocol;
  2230.                         if (pPrinterPB->pInterfaceDescriptor)
  2231.                         {
  2232.                             if (pPrinterPB->interfaceNumber == pPrinterPB->pb.usb.cntl.WIndex)
  2233.                             {
  2234.                                 pPrinterPB->pb.usbRefcon = kSetInterface;
  2235.                             }
  2236.                             else
  2237.                             {
  2238.                                 USBExpertFatalError(pPrinterPB->deviceRef, pPrinterPB->pb.usbStatus, "\p" kStrPrinterClass "kFindInterface_Bidirectional didn't find the right interface", 0);
  2239.                             }
  2240.                         }
  2241.                         else
  2242.                         {
  2243.                             pPrinterPB->pb.usbRefcon = kOpenDevice;
  2244.                             pPrinterPB->interfaceNumber = pPrinterPB->pb.usb.cntl.WIndex;
  2245.                         }
  2246.                     }
  2247.                 }
  2248.                 else
  2249.                 {
  2250.                     if ( pPrinterPB->pb.usbStatus == kUSBNotFound )
  2251.                     {
  2252.                         USBExpertStatusLevel(4, pPrinterPB->deviceRef, "\p"kStrPrinterClass"Bidirectional interface was not found", pPrinterPB->pb.usb.cntl.WIndex);
  2253.                         pPrinterPB->pb.usbRefcon = kFindInterface_unidirectional;
  2254.                     }
  2255.                     else
  2256.                     {
  2257.                         USBExpertFatalError(pPrinterPB->deviceRef, pPrinterPB->pb.usbStatus, "\p" kStrPrinterClass "kFindInterface_bidirectional failed", 0);
  2258.                         pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2259.                     }
  2260.                 }
  2261.                 break;
  2262.                 
  2263.             case kFindInterface_unidirectional:
  2264.                 USBExpertStatusLevel(5, pPrinterPB->deviceRef, "\p"kStrPrinterClass"kFindInterface_bidirectional completed", pPrinterPB->pb.usb.cntl.WIndex);
  2265.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2266.                 {
  2267.                     if ((pPrinterPB->pb.usbClassType == kUSBPrintingClass) && 
  2268.                         (pPrinterPB->pb.usbSubclass == kUSBPrinterSubclass) &&
  2269.                         (pPrinterPB->pb.usbProtocol == kUSBPrinterBidirectionalProtocol))
  2270.                     {
  2271.                         USBExpertStatusLevel(5, pPrinterPB->deviceRef, "\p"kStrPrinterClass"Found unidirection interface at alt setting ", pPrinterPB->pb.usbOther);
  2272.                         pPrinterPB->pb.usbRefcon = kOpenDevice;
  2273.                         pPrinterPB->configurationNumber = pPrinterPB->pb.usb.cntl.WValue;
  2274.                         pPrinterPB->alternateSetting = pPrinterPB->pb.usbOther;
  2275.                         pPrinterPB->printerProtocol = kUSBPrinterUnidirectionalProtocol;
  2276.                         if (pPrinterPB->pInterfaceDescriptor)
  2277.                         {
  2278.                             if (pPrinterPB->interfaceNumber == pPrinterPB->pb.usb.cntl.WIndex)
  2279.                             {
  2280.                                 pPrinterPB->pb.usbRefcon = kSetInterface;
  2281.                             }
  2282.                             else
  2283.                             {
  2284.                                 USBExpertFatalError(pPrinterPB->deviceRef, pPrinterPB->pb.usbStatus, "\p" kStrPrinterClass "kFindInterface_Unidirectional didn't find the right interface", 0);
  2285.                             }
  2286.                         }
  2287.                         else
  2288.                         {
  2289.                             pPrinterPB->pb.usbRefcon = kOpenDevice;
  2290.                             pPrinterPB->interfaceNumber = pPrinterPB->pb.usb.cntl.WIndex;
  2291.                         }
  2292.                     }
  2293.                 }
  2294.                 else
  2295.                 {
  2296.                     if ( pPrinterPB->pb.usbStatus == kUSBNotFound )
  2297.                     {
  2298.                         USBExpertStatusLevel(4, pPrinterPB->deviceRef, "\p"kStrPrinterClass"Unidirectional interface was not found", pPrinterPB->pb.usb.cntl.WIndex);
  2299.                         pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2300.                     }
  2301.                     else
  2302.                     {
  2303.                         USBExpertFatalError(pPrinterPB->deviceRef, pPrinterPB->pb.usbStatus, "\p" kStrPrinterClass "kFindInterface_unidirectional failed", 0);
  2304.                         pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2305.                     }
  2306.                 }
  2307.                 break;
  2308.                 
  2309.             case kOpenDevice:
  2310.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2311.                 {
  2312.                     USBExpertStatusLevel(5, pPrinterPB->deviceRef, "\p"kStrPrinterClass"kOpenDevice completed", pPrinterPB->pb.usbStatus);
  2313.                     pPrinterPB->pb.usbRefcon = kNewInterfaceRef;
  2314.                 }
  2315.                 else
  2316.                 {
  2317.                     USBExpertFatalError(pPrinterPB->deviceRef, pPrinterPB->pb.usbStatus, "\p" kStrPrinterClass "kOpenDevice failed", 0);
  2318.                     pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2319.                 }
  2320.                 break;
  2321.                 
  2322.             case kNewInterfaceRef:
  2323.                 USBExpertStatusLevel(5, pPrinterPB->deviceRef, "\p"kStrPrinterClass"kNewInterfaceRef completed", pPrinterPB->pb.usbReference);
  2324.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2325.                 {
  2326.                     pPrinterPB->interfaceRef = pPrinterPB->pb.usbReference;
  2327.                     pPrinterPB->pb.usbRefcon = kSetInterface;
  2328.                 }
  2329.                 else
  2330.                 {
  2331.                     USBExpertFatalError(pPrinterPB->deviceRef, pPrinterPB->pb.usbStatus, "\p" kStrPrinterClass "kNewInterfaceRef failed", 0);
  2332.                     pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2333.                 }
  2334.                 break;
  2335.             
  2336.             case kSetInterface:
  2337.                 USBExpertStatusLevel(5, pPrinterPB->interfaceRef, "\p"kStrPrinterClass"kSetInterface completed", 0);
  2338.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2339.                 {
  2340.                     pPrinterPB->pb.usbRefcon = kConfigureInterface;
  2341.                 }
  2342.                 else
  2343.                 {
  2344.                     USBExpertFatalError(pPrinterPB->deviceRef, pPrinterPB->pb.usbStatus, "\p" kStrPrinterClass "kSetInterface failed", 0);
  2345.                     pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2346.                 }
  2347.                 break;
  2348.             
  2349.             case kConfigureInterface:
  2350.                 USBExpertStatusLevel(5, pPrinterPB->interfaceRef, "\p"kStrPrinterClass"kConfigureInterface completed, pipes = ", pPrinterPB->pb.usbOther);
  2351.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2352.                 {
  2353.                     pPrinterPB->pipeCount = pPrinterPB->pb.usbOther;
  2354.                     pPrinterPB->pb.usbRefcon = kGetCapabilityString;
  2355.                 }
  2356.                 else
  2357.                 {
  2358.                     USBExpertFatalError(pPrinterPB->deviceRef, pPrinterPB->pb.usbStatus, "\p" kStrPrinterClass "kConfigureInterface failed", 0);
  2359.                     pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2360.                 }
  2361.                 break;
  2362.             
  2363.             case kGetCapabilityString:
  2364.                 USBExpertStatusLevel(5, pPrinterPB->interfaceRef, "\p"kStrPrinterClass"kGetCapabilityString completed", pPrinterPB->pb.usbStatus);
  2365.                 length = pPrinterPB->pCapabilityString[1] | (pPrinterPB->pCapabilityString[0] << 8);
  2366.     
  2367.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2368.                 {
  2369.                     //
  2370.                     //    In the short term (fall '98) several vendors are planning on shipping 
  2371.                     //        devices with a parallel port and using the Lucent USS-720 USB-to-parallel hardware.
  2372.                     //    Unfortunately this isn't an ideal solution from the USB perspective:
  2373.                     //        users can leave the printer off while the cable responds that there's
  2374.                     //        a printer connected. Then we have no way of using the DEVICE_ID
  2375.                     //        string to tag the printer and register it.
  2376.                     //    To alleviate this situation, we repeatedly poll the USS-720 if the DEVICE_ID
  2377.                     //        string is null. Every few seconds we'll retry this state.
  2378.                     //    At some point the user wants to print and switches on the printer. The class
  2379.                     //    driver then picks up from here and registers the device properly.
  2380.                     //
  2381.                     
  2382.                     if ( pPrinterPB->pb.usbActCount == 0 )
  2383.                         pPrinterPB->pb.usbRefcon = kDelayGetCapability;
  2384.                     else
  2385.                         pPrinterPB->pb.usbRefcon = kFindBulkOutPipe;
  2386.                 }
  2387.                 else
  2388.                 {
  2389.                     if ( pPrinterPB->pb.usbStatus == kUSBOverRunErr )
  2390.                     {
  2391.                         //
  2392.                         //    if we've haven't managed to read the whole capability string
  2393.                         //        we need to allocate memory and read it in by initiating kGetFullCapabilityString
  2394.                         //
  2395.     
  2396.                         if ( length > sizeof(pPrinterPB->capability) && pPrinterPB->pb.usbRefcon == kGetCapabilityString )
  2397.                         {
  2398.                             pPrinterPB->pb.usbRefcon = kAllocateCapabilityMem;
  2399.                         }    
  2400.                         
  2401.                 
  2402.                     }
  2403.                     else
  2404.                     {
  2405.                         USBExpertFatalError(pPrinterPB->interfaceRef, pPrinterPB->pb.usbStatus, "\p" kStrPrinterClass "kGetCapabilityString failed", 0);
  2406.                         pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2407.                     }
  2408.                 }
  2409.                 
  2410.                 // write the capability string to the log
  2411.                 if ((pPrinterPB->pb.usbStatus == kUSBOverRunErr)  || (pPrinterPB->pb.usbStatus == noErr))
  2412.                 {
  2413.                     if (length > 2)                     // is there a valid string? (length more than 2 bytes)
  2414.                     {
  2415.                         length -= 2;
  2416.                         if (length > 230)                // cut the string off at 230 characters
  2417.                             length = 230;
  2418.                             
  2419.                         BlockMove( (Ptr)&(pPrinterPB->pCapabilityString[2]), (Ptr)tempstr2, length);
  2420.                         tempstr2[length] = '\0';        // mark the end of the cstring
  2421.                         
  2422.                         sprintf( (char *)tempstr1, (char const *) kStrPrinterClass"1284 Capability String: %s", tempstr2 );
  2423.                         CStrToPStr( (unsigned char *)tempstr2, (char *)tempstr1);    // convert it to a pstring
  2424.                     }
  2425.                     else
  2426.                     {
  2427.                         CStrCopy( (char *)tempstr2, (char const *) "\p"kStrPrinterClass"Capability string is empty!!" );
  2428.                     }
  2429.                     USBExpertStatusLevel(4,  pPrinterPB->deviceRef, tempstr2, length);
  2430.                 }
  2431.                 break;
  2432.                 
  2433.             case kDelayGetCapability:
  2434.                 USBExpertStatusLevel(5, pPrinterPB->interfaceRef, "\p"kStrPrinterClass"kDelayGetCapability completed", pPrinterPB->pb.usbStatus);
  2435.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2436.                 {
  2437.                     pPrinterPB->pb.usbRefcon = kGetCapabilityString;
  2438.                 }
  2439.                 else
  2440.                 {
  2441.                     USBExpertFatalError(pPrinterPB->interfaceRef, pPrinterPB->pb.usbStatus, "\p" kStrPrinterClass "kDelayGetCapability failed", 0);
  2442.                     pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2443.                 }
  2444.                 break;
  2445.                 
  2446.             case kAllocateCapabilityMem:
  2447.                 USBExpertStatusLevel(5, pPrinterPB->interfaceRef, "\p"kStrPrinterClass"kAllocateCapabilityMem completed", pPrinterPB->pb.usbStatus);
  2448.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2449.                 {
  2450.                     pPrinterPB->pCapabilityString = pPrinterPB->pb.usbBuffer;
  2451.                     pPrinterPB->pb.usbRefcon = kGetFullCapabilityString;    
  2452.                 }
  2453.                 else
  2454.                 {
  2455.                     USBExpertFatalError(pPrinterPB->interfaceRef, pPrinterPB->pb.usbStatus, "\p" kStrPrinterClass "kAllocateCapabilityMem failed", 0);
  2456.                     pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2457.                 }
  2458.                 break;
  2459.             
  2460.             case kGetFullCapabilityString:
  2461.                 USBExpertStatusLevel(5, pPrinterPB->interfaceRef, "\p"kStrPrinterClass"kGetFullCapabilityString completed", pPrinterPB->pb.usbStatus);
  2462.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2463.                 {
  2464.                     pPrinterPB->pb.usbRefcon = kGetInterface;
  2465.                 }
  2466.                 else
  2467.                 {
  2468.                     USBExpertFatalError(pPrinterPB->interfaceRef, pPrinterPB->pb.usbStatus, "\p" kStrPrinterClass "kGetFullCapabilityString failed", 0);
  2469.                     pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2470.                 }
  2471.                 break;
  2472.                 
  2473.             case kGetInterface:
  2474.                 USBExpertStatusLevel(5, pPrinterPB->interfaceRef, "\p"kStrPrinterClass"kGetInterface completed", pPrinterPB->pb.usbStatus);
  2475.                 if (( pPrinterPB->pb.usbStatus == noErr ) && (pPrinterPB->whichAltInterface == pPrinterPB->alternateSetting))
  2476.                 {
  2477.                     pPrinterPB->pb.usbRefcon = kFindBulkOutPipe;
  2478.                 }
  2479.                 else
  2480.                 {
  2481.                     USBExpertFatalError(pPrinterPB->interfaceRef, pPrinterPB->pb.usbStatus, "\p" kStrPrinterClass "kGetInterface - wrong interface selected", pPrinterPB->whichAltInterface);
  2482.                     pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2483.                 }
  2484.                 break;
  2485.  
  2486.             case kFindBulkOutPipe:
  2487.                 USBExpertStatusLevel(5, pPrinterPB->interfaceRef, "\p" kStrPrinterClass"kFindBulkOutPipe completed", pPrinterPB->pb.usbReference);
  2488.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2489.                 {
  2490.                     pPrinterPB->writePipeRef = pPrinterPB->pb.usbReference;             // remember the ref
  2491.                     pPrinterPB->out = pPrinterPB->pb;                                    // copy the paramblock
  2492.                     pPrinterPB->out.usbCompletion =  (USBCompletion) NULL;                // for finalize
  2493.  
  2494.                     if ( pPrinterPB->printerProtocol == kUSBPrinterBidirectionalProtocol )
  2495.                         pPrinterPB->pb.usbRefcon = kFindBulkInPipe;
  2496.                     else
  2497.                         pPrinterPB->pb.usbRefcon = kTaskTimeRequired;
  2498.                 }
  2499.                 else
  2500.                 {
  2501.                     USBExpertFatalError(pPrinterPB->interfaceRef, pPrinterPB->pb.usbStatus, "\p" kStrPrinterClass "kFindBulkOutPipe failed", 0);
  2502.                     pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2503.                 }
  2504.                 break;
  2505.                 
  2506.             case kFindBulkInPipe:
  2507.                 USBExpertStatusLevel(5, pPrinterPB->interfaceRef, "\p"kStrPrinterClass"kFindBulkInPipe completed", pPrinterPB->pb.usbReference);
  2508.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2509.                 {
  2510.                     pPrinterPB->readPipeRef = pPrinterPB->pb.usbReference;
  2511.                     pPrinterPB->in = pPrinterPB->pb;                                    // copy the paramblock
  2512.                     pPrinterPB->in.usbCompletion =  (USBCompletion) NULL;                // for finalize
  2513.  
  2514.                     pPrinterPB->pb.usbRefcon = kTaskTimeRequired;
  2515.                 }
  2516.                 else
  2517.                 {
  2518.                     USBExpertFatalError(pPrinterPB->interfaceRef, pPrinterPB->pb.usbStatus, "\p" kStrPrinterClass "kFindBulkInPipe failed", 0);
  2519.                     pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2520.                 }
  2521.                 break;
  2522.                 
  2523.             case kTaskTimeRequired:
  2524.                 USBExpertStatusLevel(5, pPrinterPB->interfaceRef, "\p"kStrPrinterClass"kTaskTimeRequired completed (now at task time)", pPrinterPB->pb.usbReference);
  2525.             //
  2526.             //    once we know what device we're dealing with
  2527.             //        open the i/o channel(s) to the device
  2528.             //        and enter it in the name registry
  2529.             //
  2530.                 
  2531.                 err = InstallDrivers( pPrinterPB );
  2532.                 if ( err == noErr )
  2533.                 {
  2534.                     USBExpertStatusLevel(5, pPrinterPB->interfaceRef, "\p"kStrPrinterClass"kTaskTimeRequired - drivers installed", pPrinterPB->pb.usbReference);
  2535.                     err = RegisterDevice( pPrinterPB );
  2536.                     if ( err == noErr )
  2537.                     {
  2538.                         USBExpertStatusLevel(5, pPrinterPB->interfaceRef, "\p"kStrPrinterClass"kTaskTimeRequired - RegisterDevice successful", pPrinterPB->pb.usbReference);
  2539.                     }
  2540.                     else
  2541.                     {
  2542.                         USBExpertFatalError(pPrinterPB->interfaceRef, err, "\p" kStrPrinterClass "kTaskTimeRequired - RegisterDevice failed", 0);
  2543.                     }
  2544.                 }
  2545.                 else
  2546.                 {
  2547.                     USBExpertFatalError(pPrinterPB->interfaceRef, err, "\p" kStrPrinterClass "kTaskTimeRequired - InstallDrivers failed", 0);
  2548.                 }
  2549.     
  2550.                 pPrinterPB->pb.usbCompletion = (USBCompletion) NULL;                    // Finalize
  2551.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2552.                 {
  2553.                     pPrinterPB->pb.usbRefcon = kReturnFromDriver;
  2554.                     pPrinterPB->printerConfigured = true;
  2555.                 }
  2556.                 else
  2557.                 {
  2558.                     USBExpertFatalError(pPrinterPB->interfaceRef, pPrinterPB->pb.usbStatus, "\p" kStrPrinterClass "RegisterDevice failed", 0);
  2559.                     pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2560.                 }
  2561.                 break;
  2562.                 
  2563.             case kGetCentronicsStatus:
  2564.                 //
  2565.                 //    if InitiateTransaction fell through on it's kTaskTimeRequired case we'll end up here
  2566.                 //
  2567.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2568.                 {
  2569.                     unsigned char text[255];
  2570.                     sprintf( (char *)text, " Centronics Status: 0x%02x", pPrinterPB->centronics.b );
  2571.                     text[0] = CStrLen((char *)text); // c2pstr
  2572.                     USBExpertStatusLevel(5, pPrinterPB->interfaceRef, text, pb->usbStatus );
  2573.                     
  2574. #if DEBUG
  2575.                     if ( !pPrinterPB->centronics.status.notError )
  2576.                     {
  2577.                         USBExpertStatusLevel(5, pPrinterPB->interfaceRef, "\p" kStrPrinterClass "Error at printer", pPrinterPB->pb.usbStatus);
  2578.                     }
  2579.                     if ( pPrinterPB->centronics.status.paperError )
  2580.                     {
  2581.                         USBExpertStatusLevel(5, pPrinterPB->interfaceRef, "\p" kStrPrinterClass "Check paper", pPrinterPB->pb.usbStatus);
  2582.                     }
  2583.                     if ( !pPrinterPB->centronics.status.select )
  2584.                     {
  2585.                         USBExpertStatusLevel(5, pPrinterPB->interfaceRef, "\p" kStrPrinterClass "printer offline", pPrinterPB->pb.usbStatus);
  2586.                     }
  2587. #endif
  2588.                     pPrinterPB->pb.usbRefcon = kDelayGetCentronicsStatus;
  2589.                 }
  2590.                 else
  2591.                 {
  2592.                     USBExpertStatusLevel(5, pPrinterPB->interfaceRef, "\p"kStrPrinterClass"kGetCentronicsStatus - error getting centronics status", pPrinterPB->pb.usbStatus);
  2593.                 }
  2594.                 break;
  2595.                 
  2596.             case kDelayGetCentronicsStatus:
  2597.                 //
  2598.                 //    loop around continually getting status
  2599.                 //
  2600.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2601.                 {
  2602.                     pPrinterPB->pb.usbRefcon = kGetCentronicsStatus;
  2603.                 }
  2604.                 break;
  2605.             case kNilCompletion:
  2606.             default:
  2607.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2608.                     pPrinterPB->pb.usbRefcon = kUndefined | kReturnFromDriver;
  2609.                 break;
  2610.         }
  2611.     }
  2612.     
  2613.     // did the removal notification get called?  If so, don't start another transaction.  Just exit
  2614.    if (!pPrinterPB->terminating)
  2615.     {
  2616.         if (pPrinterPB->pb.usbStatus == noErr )
  2617.         {
  2618.             if (!(pPrinterPB->pb.usbRefcon & kReturnFromDriver))
  2619.                 PrinterDeviceInitiateTransaction(pb);
  2620.         }
  2621.         else if ( pPrinterPB->pb.usbRefcon & kReturnFromDriver)
  2622.         {
  2623.             USBExpertFatalError(pPrinterPB->deviceRef, pPrinterPB->pb.usbStatus, StateStr(pPrinterPB->pb.usbRefcon, kPString), pPrinterPB->pb.usbRefcon);
  2624.             USBExpertFatalError(pPrinterPB->deviceRef, pPrinterPB->pb.usbStatus, USBStatusStr(pPrinterPB->pb.usbStatus, kPString), 0);
  2625.         }
  2626.     }
  2627.     else
  2628.     {
  2629.         pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2630.     }
  2631.     
  2632.     // If we're exiting the driver, then make certain the completion routine is set to NULL
  2633.     // this lets the driver removal task know that there's nothing pending.
  2634.     if ( pPrinterPB->pb.usbRefcon & kReturnFromDriver)
  2635.     {
  2636.         pPrinterPB->pb.usbCompletion    = (USBCompletion) NULL;
  2637.     }
  2638. }
  2639.  
  2640. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2641.     Name:        PrinterDeviceInitiateTransaction
  2642.  
  2643.     Input Parameters:    
  2644.         pb            USB parameter block
  2645.         
  2646.     Output Parameters:
  2647.         
  2648.     Description:
  2649.         Since USB transactions are asynchronous we use the refCon field
  2650.         in the parameter block to implement the following logic via a state machine.
  2651.  
  2652.         Start out by getting the device configuration descriptor
  2653.         If the device has more than one printing interface
  2654.             If a bidirectional interface exists
  2655.                 select it
  2656.             Else
  2657.                 select the (mandatory) unidirectional interface
  2658.         Get the (mandatory) 1284 capability string
  2659.         Open pipes to the BulkOut (and optional BulkIn) endpoints
  2660.         Install read and write drivers in the unit table
  2661.         Using information from the capability string
  2662.             enter the printer in the MacOS name registry.
  2663.         
  2664.  
  2665.  
  2666.  
  2667.  
  2668.  
  2669.  
  2670. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  2671. void
  2672. PrinterDeviceInitiateTransaction(USBPB *pb)
  2673. {
  2674. register struct usbPrinterPBStruct    *pPrinterPB;
  2675. int            length;
  2676. OSStatus    err;
  2677.  
  2678.     pPrinterPB = (struct usbPrinterPBStruct *)(pb);
  2679.     
  2680.     pPrinterPB->transDepth++;
  2681.     if ((pPrinterPB->transDepth < 0) || (pPrinterPB->transDepth > 1))
  2682.     {
  2683.         USBExpertFatalError(pPrinterPB->deviceRef, kUSBInternalErr, "\p" kStrPrinterClass "InitiateTransaction illegal transaction depth", 0);
  2684.     }
  2685.     IF_DEBUG( USBExpertStatus( pPrinterPB->deviceRef, StateStr(pPrinterPB->pb.usbRefcon, kPString), 0) );     
  2686.     
  2687.     pPrinterPB->delayInProgress = false;
  2688.     switch(pPrinterPB->pb.usbRefcon & ~kRetryTransaction)
  2689.     {
  2690.         case kFindInterface_bidirectional:
  2691.             USBExpertStatusLevel(5, pPrinterPB->deviceRef, "\p" kStrPrinterClass"kFindInterface_bidirectional", 0);
  2692.             SetNullUSBParamBlock( pPrinterPB->deviceRef, &pPrinterPB->pb );
  2693.             
  2694.             pPrinterPB->pb.usbBuffer = 0;
  2695.             pPrinterPB->pb.usbActCount = 0;
  2696.             pPrinterPB->pb.usbReqCount = 0;
  2697.             pPrinterPB->pb.usb.cntl.WIndex = 0;
  2698.             pPrinterPB->pb.usb.cntl.WValue = 0;
  2699.             pPrinterPB->pb.usbClassType = kUSBPrintingClass;
  2700.             pPrinterPB->pb.usbSubclass = kUSBPrinterSubclass;
  2701.             pPrinterPB->pb.usbProtocol = kUSBPrinterBidirectionalProtocol;
  2702.             
  2703.             pPrinterPB->pb.usbRefcon |= kTransactionPending;
  2704.             pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  2705.             err = USBFindNextInterface(pb);
  2706.             if(immediateError(err))
  2707.             {
  2708.                 USBExpertFatalError(pPrinterPB->pb.usbReference, kUSBInternalErr, "\p"kStrPrinterClass"kFindInterface_bidirectional - immediate error", err);
  2709.                 pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2710.             }
  2711.             break;
  2712.     
  2713.         case kFindInterface_unidirectional:
  2714.             USBExpertStatusLevel(5, pPrinterPB->deviceRef, "\p" kStrPrinterClass"kFindInterface_unidirectional", 0);
  2715.             SetNullUSBParamBlock( pPrinterPB->deviceRef, &pPrinterPB->pb );
  2716.             
  2717.             pPrinterPB->pb.usbBuffer = 0;
  2718.             pPrinterPB->pb.usbActCount = 0;
  2719.             pPrinterPB->pb.usbReqCount = 0;
  2720.             pPrinterPB->pb.usb.cntl.WIndex = 0;
  2721.             pPrinterPB->pb.usb.cntl.WValue = 0;
  2722.             pPrinterPB->pb.usbClassType = kUSBPrintingClass;
  2723.             pPrinterPB->pb.usbSubclass = kUSBPrinterSubclass;
  2724.             pPrinterPB->pb.usbProtocol = kUSBPrinterUnidirectionalProtocol;
  2725.             
  2726.             pPrinterPB->pb.usbRefcon |= kTransactionPending;
  2727.             pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  2728.             err = USBFindNextInterface(pb);
  2729.             if(immediateError(err))
  2730.             {
  2731.                 USBExpertFatalError(pPrinterPB->pb.usbReference, kUSBInternalErr, "\p"kStrPrinterClass"kFindInterface_unidirectional - immediate error", err);
  2732.                 pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2733.             }
  2734.             break;
  2735.     
  2736.         case kOpenDevice:
  2737.             USBExpertStatusLevel(5, pPrinterPB->deviceRef, "\p" kStrPrinterClass"kOpenDevice", 0);
  2738.             SetNullUSBParamBlock( pPrinterPB->deviceRef, &pPrinterPB->pb );
  2739.             
  2740.             pPrinterPB->pb.usbBuffer = 0;
  2741.             pPrinterPB->pb.usbActCount = 0;
  2742.             pPrinterPB->pb.usbReqCount = 0;
  2743.             pPrinterPB->pb.usb.cntl.WValue = pPrinterPB->configurationNumber;
  2744.             
  2745.             pPrinterPB->pb.usbRefcon |= kTransactionPending;
  2746.             pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  2747.             err = USBOpenDevice(pb);
  2748.             if(immediateError(err))
  2749.             {
  2750.                 USBExpertFatalError(pPrinterPB->pb.usbReference, kUSBInternalErr, "\p"kStrPrinterClass"USBOpenDevice - immediate error", err);
  2751.                 pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2752.             }
  2753.             break;
  2754.             
  2755.         case kNewInterfaceRef:
  2756.             USBExpertStatusLevel(5, pPrinterPB->deviceRef, "\p" kStrPrinterClass"kNewInterfaceRef for interface number", pPrinterPB->interfaceNumber);
  2757.             SetNullUSBParamBlock( pPrinterPB->deviceRef, &pPrinterPB->pb );
  2758.             
  2759.             pPrinterPB->pb.usbBuffer = 0;
  2760.             pPrinterPB->pb.usbActCount = 0;
  2761.             pPrinterPB->pb.usbReqCount = 0;
  2762.             pPrinterPB->pb.usb.cntl.WIndex = pPrinterPB->interfaceNumber;
  2763.             
  2764.             pPrinterPB->pb.usbRefcon |= kTransactionPending;
  2765.             pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  2766.             err = USBNewInterfaceRef(pb);
  2767.             if(immediateError(err))
  2768.             {
  2769.                 USBExpertFatalError(pPrinterPB->pb.usbReference, kUSBInternalErr, "\p"kStrPrinterClass"USBNewInterfaceRef - immediate error", err);
  2770.                 pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2771.             }
  2772.             break;
  2773.             
  2774.  
  2775.         case kSetInterface:
  2776.             USBExpertStatusLevel(5, pPrinterPB->interfaceRef, "\p" kStrPrinterClass"kSetInterface to alternate setting", pPrinterPB->alternateSetting);
  2777.             SetNullUSBParamBlock( pPrinterPB->interfaceRef, &pPrinterPB->pb );
  2778.             
  2779.             pPrinterPB->pb.usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBStandard, kUSBInterface);
  2780.         
  2781.             pPrinterPB->pb.usb.cntl.BRequest = kUSBRqSetInterface;
  2782.             pPrinterPB->pb.usb.cntl.WValue = pPrinterPB->alternateSetting;        // alternate setting
  2783.             pPrinterPB->pb.usb.cntl.WIndex = pPrinterPB->interfaceNumber;        // interface
  2784.         
  2785.             pPrinterPB->pb.usbReqCount = 0;
  2786.             pPrinterPB->pb.usbBuffer = NULL;
  2787.         
  2788.             pPrinterPB->pb.usbRefcon |= kTransactionPending;
  2789.             pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  2790.             err = USBDeviceRequest(pb);
  2791.             if(immediateError(err))
  2792.             {
  2793.                 USBExpertFatalError(pPrinterPB->pb.usbReference, kUSBInternalErr, "\p"kStrPrinterClass"kSetInterface - immediate error", err);
  2794.                 pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2795.             }
  2796.             break;
  2797.  
  2798.  
  2799.         case kConfigureInterface:
  2800.             USBExpertStatusLevel(5, pPrinterPB->interfaceRef, "\p" kStrPrinterClass"kConfigureInterface for alternate setting", pPrinterPB->alternateSetting);
  2801.             SetNullUSBParamBlock( pPrinterPB->interfaceRef, &pPrinterPB->pb );
  2802.             
  2803.             pPrinterPB->pb.usbBuffer = 0;
  2804.             pPrinterPB->pb.usbActCount = 0;
  2805.             pPrinterPB->pb.usbReqCount = 0;
  2806.             pPrinterPB->pb.usbOther = pPrinterPB->alternateSetting;
  2807.             
  2808.             pPrinterPB->pb.usbRefcon |= kTransactionPending;
  2809.             pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  2810.             err = USBConfigureInterface(pb);
  2811.             if(immediateError(err))
  2812.             {
  2813.                 USBExpertFatalError(pPrinterPB->pb.usbReference, kUSBInternalErr, "\p"kStrPrinterClass"USBConfigureInterface - immediate error)", err);
  2814.                 pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2815.             }
  2816.             break;
  2817.             
  2818.         case kGetCapabilityString:
  2819.             //
  2820.             //    once the interface (and alternate) is assinged
  2821.             //        we can retreive the 1284 capability string to see what kind of printer
  2822.             //        is attached
  2823.             USBExpertStatusLevel(5, pPrinterPB->interfaceRef, "\p" kStrPrinterClass"kGetCapabilityString", 0);
  2824.             pPrinterPB->pCapabilityString = pPrinterPB->capability;
  2825.             
  2826.             GetCapability( pPrinterPB, pPrinterPB->pCapabilityString, sizeof(pPrinterPB->capability) );
  2827.             break;
  2828.             
  2829.         case kDelayGetCapability:
  2830.             //
  2831.             //    USS-720 USB-parallel cable: couldn't get the capability string because the printer is off
  2832.             //        Delay a few seconds and try again.
  2833.             //        Will succeed when the user turns the printer on.
  2834.             //
  2835.             USBExpertStatusLevel(5, pPrinterPB->interfaceRef, "\p" kStrPrinterClass"kDelayGetCapability", 0);
  2836.             SetNullUSBParamBlock( pPrinterPB->interfaceRef, &pPrinterPB->pb );
  2837.             
  2838.             pPrinterPB->pb.usbBuffer = 0;
  2839.             pPrinterPB->pb.usbActCount = 0;
  2840.             pPrinterPB->pb.usbReqCount = kUSS720MillisecondDelay;
  2841.             pPrinterPB->pb.usbFlags = kUSBTaskTimeFlag;
  2842.             
  2843.             pPrinterPB->pb.usbRefcon |= kTransactionPending;
  2844.             pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  2845.             pPrinterPB->delayInProgress = true;
  2846.             err = USBDelay(&pPrinterPB->pb);
  2847.             if(immediateError(err))
  2848.             {
  2849.                 USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "kDelayGetCapability - immediate error", 0);
  2850.                 pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2851.             }
  2852.             break;
  2853.             
  2854.         case kAllocateCapabilityMem:
  2855.             USBExpertStatusLevel(5, pPrinterPB->interfaceRef, "\p" kStrPrinterClass"kAllocateCapabilityMem", 0);
  2856.             SetNullUSBParamBlock( pPrinterPB->interfaceRef, &pPrinterPB->pb );
  2857.             
  2858.             length = pPrinterPB->capability[1] | (pPrinterPB->capability[0]<<8);
  2859.             pPrinterPB->pb.usbBuffer = 0;
  2860.             pPrinterPB->pb.usbActCount = 0;
  2861.             pPrinterPB->pb.usbReqCount = length;
  2862.             pPrinterPB->pb.usbFlags = 0;
  2863.             
  2864.             pPrinterPB->pb.usbRefcon |= kTransactionPending;
  2865.             pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  2866.             err = USBAllocMem(&pPrinterPB->pb);
  2867.             if(immediateError(err))
  2868.             {
  2869.                 USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "kAllocateCapabilityMem - immediate error", 0);
  2870.                 pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2871.             }
  2872.             break;
  2873.         
  2874.         case kGetFullCapabilityString:
  2875.             //
  2876.             // the capability string was too long to fit in the statically allocated space
  2877.             // need to release this memory when we finalize our driver
  2878.             //
  2879.  
  2880.             USBExpertStatusLevel(5, pPrinterPB->interfaceRef, "\p" kStrPrinterClass"kGetFullCapabilityString", 0);
  2881.             length = pPrinterPB->capability[1] | (pPrinterPB->capability[0]<<8);
  2882.             if ( pPrinterPB->pCapabilityString )
  2883.                 GetCapability( pPrinterPB, pPrinterPB->pCapabilityString, length );
  2884.             else
  2885.                 USBExpertFatalError(pPrinterPB->interfaceRef, kUSBInternalErr, "\p" kStrPrinterClass "Can't allocate capability memory", 0);
  2886.             break;
  2887.             
  2888.         case kGetInterface:
  2889.             // failsafe check that we've got the right setup
  2890.             //    it's possible the device didn't respond to our SetInterface
  2891.             GetInterface( &pPrinterPB->pb, &pPrinterPB->whichAltInterface );
  2892.             break;
  2893.  
  2894.         case kFindBulkOutPipe:
  2895.             USBExpertStatusLevel(5, pPrinterPB->interfaceRef, "\p" kStrPrinterClass"kFindBulkOutPipe", 0);
  2896.             SetNullUSBParamBlock( pPrinterPB->interfaceRef, &pPrinterPB->pb );
  2897.             
  2898.             pPrinterPB->pb.usbBuffer = 0;
  2899.             pPrinterPB->pb.usbActCount = 0;
  2900.             pPrinterPB->pb.usbReqCount = 0;
  2901.             pPrinterPB->pb.usbFlags = kUSBOut;
  2902.             pPrinterPB->pb.usbClassType = kUSBBulk;
  2903.             
  2904.             pPrinterPB->pb.usbRefcon |= kTransactionPending;
  2905.             pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  2906.             err = USBFindNextPipe( &pPrinterPB->pb );
  2907.             if (immediateError(err))
  2908.             {
  2909.                 USBExpertFatalError(pPrinterPB->interfaceRef, kUSBInternalErr, kStrPrinterClass"kFindBulkOutPipe - immediate error", err);
  2910.                 pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2911.             }
  2912.             break;
  2913.             
  2914.         case kFindBulkInPipe:    
  2915.             USBExpertStatusLevel(5, pPrinterPB->interfaceRef, "\p" kStrPrinterClass"kFindBulkInPipe", 0);
  2916.             SetNullUSBParamBlock( pPrinterPB->interfaceRef, &pPrinterPB->pb );
  2917.             
  2918.             pPrinterPB->pb.usbBuffer = 0;
  2919.             pPrinterPB->pb.usbActCount = 0;
  2920.             pPrinterPB->pb.usbReqCount = 0;
  2921.             pPrinterPB->pb.usbFlags = kUSBIn;
  2922.             pPrinterPB->pb.usbClassType = kUSBBulk;
  2923.             
  2924.             pPrinterPB->pb.usbRefcon |= kTransactionPending;
  2925.             pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  2926.             err = USBFindNextPipe( &pPrinterPB->pb );
  2927.             if (immediateError(err))
  2928.             {
  2929.                 USBExpertFatalError(pPrinterPB->interfaceRef, kUSBInternalErr, "\p"kStrPrinterClass"kFindBulkInPipe - immediate error", err);
  2930.                 pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2931.             }
  2932.             break;
  2933.             
  2934.         case kTaskTimeRequired:
  2935.             USBExpertStatusLevel(5, pPrinterPB->interfaceRef, "\p" kStrPrinterClass"kTaskTimeRequired", 0);
  2936.              // to stress test usb bus, fallthrough to kGetCentronicsStatus 
  2937.             SetNullUSBParamBlock( pPrinterPB->interfaceRef, &pPrinterPB->pb );
  2938.             
  2939.             pPrinterPB->pb.usbBuffer = 0;
  2940.             pPrinterPB->pb.usbActCount = 0;
  2941.             pPrinterPB->pb.usbReqCount = kUSBNoDelay;
  2942.             pPrinterPB->pb.usbFlags = kUSBTaskTimeFlag;
  2943.             
  2944.             pPrinterPB->pb.usbRefcon |= kTransactionPending;
  2945.             pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  2946.             pPrinterPB->delayInProgress = true;
  2947.             err = USBDelay(&pPrinterPB->pb);
  2948.             if(immediateError(err))
  2949.             {
  2950.                 USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "kTaskTimeRequired - immediate error", 0);
  2951.                 pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2952.             }
  2953.             break;
  2954.  
  2955.         case kGetCentronicsStatus:
  2956.             SetNullUSBParamBlock( pPrinterPB->interfaceRef, &pPrinterPB->pb );
  2957.  
  2958.             CentronicsStatus( &pPrinterPB->pb,  &pPrinterPB->centronics.b, pPrinterPB->interfaceNumber );
  2959.             
  2960.             pPrinterPB->pb.usbRefcon |= kTransactionPending;
  2961.             pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  2962.             err = USBDeviceRequest(&pPrinterPB->pb);
  2963.             if(immediateError(err))
  2964.             {
  2965.                 USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "kGetCentronicsStatus Immediate error", 0);
  2966.                 pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2967.             }
  2968.             break;
  2969.             
  2970.         case kDelayGetCentronicsStatus:
  2971.             SetNullUSBParamBlock( pPrinterPB->interfaceRef, &pPrinterPB->pb );
  2972.  
  2973.             pPrinterPB->pb.usbBuffer = 0;
  2974.             pPrinterPB->pb.usbActCount = 0;
  2975.             pPrinterPB->pb.usbReqCount = kUSS720StatusMSDelay;
  2976.             
  2977.             pPrinterPB->pb.usbRefcon |= kTransactionPending;
  2978.             pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  2979.             pPrinterPB->delayInProgress = true;
  2980.             err = USBDelay(&pPrinterPB->pb);
  2981.             if(immediateError(err))
  2982.             {
  2983.                 USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "kDelayGetCentronicsStatus - immediate error", 0);
  2984.                 pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2985.             }
  2986.             break;
  2987.             
  2988.         default:
  2989.             USBExpertFatalError(pPrinterPB->deviceRef, kUSBInternalErr, "\p" kStrPrinterClass "InitiateTransaction - unknown state", pPrinterPB->pb.usbRefcon);
  2990.             pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2991.             break;
  2992.     }
  2993.     
  2994.     if (pPrinterPB->pb.usbRefcon & kReturnFromDriver)
  2995.     {
  2996.         pPrinterPB->pb.usbCompletion = (USBCompletion) NULL;
  2997.     }
  2998. }
  2999.  
  3000.  
  3001. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  3002.     Name:        PrintDriverEntry
  3003.  
  3004.     Input Parameters:    
  3005.         
  3006.     Output Parameters:
  3007.         
  3008.     Description:
  3009.         This is where the system instantiates a USB printing device.
  3010.  
  3011.         We need to install drivers in the MacOS unitTable, and a reference
  3012.         in the name registry.
  3013.         
  3014.         But the information we need to do this is only available after some 
  3015.         USB transactions have completed. So we initiate here a series of asynchronous
  3016.         USB operations to get that information (by calling the first 
  3017.  
  3018.  
  3019.  
  3020.  
  3021.  
  3022. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  3023. void 
  3024. PrintDriverEntry(
  3025.     USBDeviceRef                    deviceRef,
  3026.     USBDeviceDescriptorPtr        pDeviceDesc,
  3027.     USBInterfaceDescriptorPtr    pInterfaceDesc,
  3028.     UInt32                            interfaceNumber
  3029.     )
  3030. {
  3031.     static Boolean        beenThereDoneThat = false;
  3032.     OSStatus                err;
  3033.     
  3034.     
  3035.     RoutineDescriptor qw = BUILD_ROUTINE_DESCRIPTOR( uppQueueUSBWriteProcInfo, QueueWrite);
  3036.     RoutineDescriptor qr = BUILD_ROUTINE_DESCRIPTOR( uppQueueUSBReadProcInfo, QueueRead);
  3037.     RoutineDescriptor qa = BUILD_ROUTINE_DESCRIPTOR( uppAbortProcInfo, Abort);
  3038.     RoutineDescriptor qs = BUILD_ROUTINE_DESCRIPTOR( uppControlStatusProcInfo, ControlStatusRequests );
  3039.     
  3040.     if( !beenThereDoneThat)
  3041.     {
  3042.         printerClassRecord.terminating = false;
  3043.         printerClassRecord.printerRegistered = false;
  3044.         beenThereDoneThat = true;
  3045.         
  3046.         //DebugStr("\pIn Printer Driver Entry");
  3047.         USBExpertStatusLevel(4, deviceRef, "\p"kStrPrinterClass"Starting USB Printer Driver", 0);
  3048.         
  3049.         printerClassRecord.deviceDescriptor = *pDeviceDesc;    /* keep a copy of the device descriptor */
  3050.         printerClassRecord.pInterfaceDescriptor = pInterfaceDesc;
  3051.         printerClassRecord.interfaceNumber = interfaceNumber;
  3052.         
  3053.         printerClassRecord.deviceRef = deviceRef;
  3054.         printerClassRecord.interfaceRef = deviceRef;
  3055.         
  3056.         printerClassRecord.transDepth = 0;            /* init Delay Callback Depth */
  3057.     
  3058.         printerClassRecord.inRefNum =  -1;            /* initially no DRVRs added to UnitTable */
  3059.         printerClassRecord.outRefNum =  -1;    
  3060.         err = LoadResources( &printerClassRecord );
  3061.         if ( err != noErr )  
  3062.             USBExpertFatalError( deviceRef, err, "\p" kStrPrinterClass "LoadResources failed", 0);
  3063.         //
  3064.         //    routines to write and read to the device must be called by 68K DRVR
  3065.         //        so we use mixed-mode manager to dispatch between PPC and 68K
  3066.         //
  3067.         printerClassRecord.qwrite = (QueueUSBWriteUPP) &printerClassRecord.qwriteRD;
  3068.         printerClassRecord.qwriteRD = qw;
  3069.     
  3070.         printerClassRecord.qread = (QueueUSBReadUPP) &printerClassRecord.qreadRD;
  3071.         printerClassRecord.qreadRD = qr;    
  3072.         
  3073.         printerClassRecord.qstatus = (ControlStatusUPP) &printerClassRecord.qstatusRD;
  3074.         printerClassRecord.qstatusRD = qs;
  3075.  
  3076.         printerClassRecord.qabort = (AbortUPP) &printerClassRecord.qabortRD;
  3077.         printerClassRecord.qabortRD = qa;
  3078.  
  3079.         printerClassRecord.r = (QueueUSBReadUPP) QueueRead;
  3080.         printerClassRecord.w = (QueueUSBWriteUPP) QueueWrite;
  3081.         printerClassRecord.s = (ControlStatusUPP) ControlStatusRequests;
  3082.         printerClassRecord.a = (AbortUPP) Abort;
  3083.    
  3084.         SetNullUSBParamBlock( deviceRef, &printerClassRecord.pb );
  3085.         SetNullUSBParamBlock( 0, &printerClassRecord.in );        // fill in pipe ref later
  3086.         SetNullUSBParamBlock( 0, &printerClassRecord.out );    // fill in pipe ref later
  3087.         
  3088.         CStrCopy((char *)printerClassRecord.name, "");
  3089.         CStrCopy((char *)printerClassRecord.model, "");
  3090.  
  3091. #if DOUBLE_BUFFER
  3092.         //
  3093.         // Assume 1. TRANSFER_SIZE is a power of 2
  3094.         //    Assume 2. malignedBuffer is allocated to be 3*TRANSFER_SIZE
  3095.         //
  3096.         printerClassRecord.pageWriteAlignedBufferSize = TRANSFER_SIZE;                            // should get this from VM
  3097.         printerClassRecord.pageWriteAlignedBuffer = printerClassRecord.malignedBuffer;
  3098.         // align it below the buffer, then bring it into the range of the buffer
  3099.         *((UInt32 *) &printerClassRecord.pageWriteAlignedBuffer) &= ~(printerClassRecord.pageWriteAlignedBufferSize - 1);    //assumption1
  3100.         *((UInt32 *) &printerClassRecord.pageWriteAlignedBuffer) += printerClassRecord.pageWriteAlignedBufferSize;            //assumption2
  3101.  
  3102.         printerClassRecord.pageReadAlignedBufferSize = TRANSFER_SIZE;
  3103.         printerClassRecord.pageReadAlignedBuffer = printerClassRecord.pageWriteAlignedBuffer + TRANSFER_SIZE;
  3104. #endif
  3105.         printerClassRecord.printerConfigured = false;
  3106.     
  3107.         //
  3108.         //    Just to be thorough, lets hold our paramter blocks so that we won't page them at
  3109.         //        interrupt time. (We should be in the System heap and automatically held.)
  3110.         //
  3111.         HoldMemory( &printerClassRecord, sizeof(struct usbPrinterPBStruct) );
  3112.  
  3113.         CheckUSBVersion();
  3114.         
  3115.         //
  3116.         // Start out at first state
  3117.         //
  3118.         printerClassRecord.pCapabilityString = printerClassRecord.capability;
  3119.         printerClassRecord.pb.usbRefcon = kFindInterface_bidirectional;
  3120.         
  3121.         // don't start if we received a removal notification just as we're starting up
  3122.         if (printerClassRecord.terminating)
  3123.         {
  3124.             printerClassRecord.pb.usbCompletion    = (USBCompletion) NULL;
  3125.         }
  3126.         else
  3127.         {
  3128.             PrinterDeviceInitiateTransaction(&printerClassRecord.pb);
  3129.         }
  3130.     }
  3131. }
  3132.  
  3133. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  3134.     Name:        PrinterRemovalNotification
  3135.  
  3136.     Input Parameters:    
  3137.         
  3138.     Output Parameters:
  3139.         
  3140.     Description:
  3141.         release any allocated storage
  3142.         remove DRVRs from the UnitTable
  3143.  
  3144.         One small complication happens when the USS-720 cable is used. It's possible
  3145.         that the user has the device plugged in, but the printer wasn't powered on.
  3146.         In this case, our state machine is still cycling between the states 
  3147.         kDelayGetCapability and kGetCapabilityString. If we terminate before the delay
  3148.         returns we'll crash the system. We monitor terminating to handle this
  3149.         
  3150.  
  3151.  
  3152.  
  3153.  
  3154.  
  3155.  
  3156.  
  3157.  
  3158.  
  3159. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  3160. OSStatus
  3161. PrinterRemovalNotification( void )
  3162. {
  3163. static    Boolean    logfileclosed = false;
  3164. static    Boolean    aborted = false;
  3165. static    Boolean    deregistered = false;
  3166. static    Boolean    readpipeaborted = false;
  3167. static    Boolean    writepipeaborted = false;
  3168. static    Boolean    timedout = false;
  3169. OSStatus            result = noErr;
  3170. static unsigned long    tc = 0;
  3171.     //
  3172.     //    notify state machine not to continue
  3173.     //
  3174.     printerClassRecord.terminating = true;
  3175.     
  3176.     USBExpertStatusLevel(5,  printerClassRecord.deviceRef, "\p"kStrPrinterClass"Driver removal notification received", 0);
  3177.     if (!logfileclosed)
  3178.     {
  3179.         USBExpertStatusLevel(5,  printerClassRecord.deviceRef, "\p"kStrPrinterClass"Closing printer log file", 0);
  3180.         LOGGING( fclose( logfile ) );
  3181.         logfileclosed = true;
  3182.         return (OSStatus) kUSBDeviceBusy;
  3183.     }
  3184.     
  3185.     // per the Mac OS USB DDK API Ref 
  3186.     // "If the device associated with this call [USBDelay] is unplugged and its driver removed while
  3187.     //  this function call is pending, the function will not complete."
  3188.     // therefore don't hang around if a delay is in progress
  3189.     if (( printerClassRecord.pb.usbCompletion != (USBCompletion) NULL ) && (!printerClassRecord.delayInProgress))
  3190.     {
  3191.         USBExpertStatusLevel(5, printerClassRecord.deviceRef, "\p"kStrPrinterClass"Waiting for configuration to complete", printerClassRecord.pb.usbRefcon);
  3192.         return (OSStatus) kUSBDeviceBusy;
  3193.     }
  3194.     
  3195.     // Abort any outstanding write requests
  3196.     if (( printerClassRecord.out.usbCompletion != (USBCompletion) NULL ) && (!writepipeaborted))
  3197.     {
  3198.         USBExpertStatusLevel(5, printerClassRecord.deviceRef, "\p"kStrPrinterClass"Abort write pipe", printerClassRecord.writePipeRef);
  3199.         USBAbortPipeByReference( printerClassRecord.writePipeRef );
  3200.         writepipeaborted = true;
  3201.         return (OSStatus) kUSBDeviceBusy;
  3202.     }
  3203.     
  3204.     // Abort any outstanding read requests
  3205.     if (( printerClassRecord.in.usbCompletion != (USBCompletion) NULL ) && (!readpipeaborted))
  3206.     {
  3207.         USBExpertStatusLevel(5, printerClassRecord.deviceRef, "\p"kStrPrinterClass"Abort read pipe", printerClassRecord.readPipeRef );
  3208.         USBAbortPipeByReference( printerClassRecord.readPipeRef );
  3209.         readpipeaborted = true;
  3210.         return (OSStatus) kUSBDeviceBusy;
  3211.     }
  3212.     
  3213.     // Abort any outstanding transactions
  3214.     if (!aborted)
  3215.     {
  3216.         USBExpertStatusLevel(5, printerClassRecord.deviceRef, "\p"kStrPrinterClass"Call Abort()", 0);
  3217.         Abort( 0, &printerClassRecord );
  3218.         aborted = true;
  3219.         return (OSStatus) kUSBDeviceBusy;
  3220.     }
  3221.  
  3222.     // wait up to ten seconds for the read & write routines to complete.  When they do, the completion procptrs will be NULL'd
  3223.     if (tc == 0)
  3224.         tc = TickCount() + 10*60;
  3225.         
  3226.     if ( TickCount() >= tc )
  3227.         timedout = true;
  3228.         
  3229.     if (( TickCount() < tc ) &&
  3230.          (( printerClassRecord.out.usbCompletion != (USBCompletion) NULL) ||
  3231.           ( printerClassRecord.in.usbCompletion != (USBCompletion) NULL )))
  3232.     {
  3233.         return (OSStatus) kUSBDeviceBusy;
  3234.     }
  3235.     
  3236.     // Put the appropriate timeout message in the log
  3237.     if ( timedout )
  3238.     {
  3239.         USBExpertStatusLevel(4, printerClassRecord.deviceRef, "\p"kStrPrinterClass"took longer than 10 seconds for read/write pipes to complete", 0);
  3240.     }
  3241.     else
  3242.     {
  3243.         USBExpertStatusLevel(4, printerClassRecord.deviceRef, "\p"kStrPrinterClass"Pipes closed normally", 0);
  3244.     }
  3245.     
  3246.     if (( printerClassRecord.out.usbCompletion != (USBCompletion) NULL) ||
  3247.           ( printerClassRecord.in.usbCompletion != (USBCompletion) NULL ))
  3248.     {
  3249.         USBExpertStatusLevel(5, printerClassRecord.deviceRef, "\p"kStrPrinterClass"Completion procs are not nil!!", 0);
  3250.     }
  3251.     
  3252.     // if the printer was never registered, then don't try to deregister it
  3253.     if (!(printerClassRecord.printerRegistered))
  3254.         deregistered = true;
  3255.         
  3256.     if (!deregistered)    
  3257.     {
  3258.         //
  3259.         //    remove printer from the name registry
  3260.         //
  3261.         USBExpertStatusLevel(5, printerClassRecord.deviceRef, "\p"kStrPrinterClass"Removed printer entry from nameregistry", 0);
  3262.         DeregisterDevice( &printerClassRecord );
  3263.         deregistered = true;
  3264.         return (OSStatus) kUSBDeviceBusy;
  3265.     }
  3266.  
  3267.     //
  3268.     //    release any allocated storage
  3269.     //
  3270.     if ( printerClassRecord.pCapabilityString != printerClassRecord.capability )
  3271.     {
  3272.         USBExpertStatusLevel(5, printerClassRecord.deviceRef, "\p"kStrPrinterClass"Deallocated capability string memory", 0);
  3273.         printerClassRecord.pb.usbReference = printerClassRecord.deviceRef;             
  3274.         printerClassRecord.pb.usbFlags = 0;             
  3275.         printerClassRecord.pb.usbRefcon = kDeallocateCapbilityString;             
  3276.         printerClassRecord.pb.usbBuffer = printerClassRecord.pCapabilityString;        
  3277.         printerClassRecord.pb.usbCompletion = (USBCompletion)kUSBNoCallBack;
  3278.         printerClassRecord.delayInProgress = true;        // this prevents the control pipe completion procptr from being checked
  3279.         USBDeallocMem(&printerClassRecord.pb);
  3280.         
  3281.         printerClassRecord.pCapabilityString = printerClassRecord.capability;
  3282.         return (OSStatus) kUSBDeviceBusy;
  3283.     }
  3284.  
  3285.     //
  3286.     //    don't need to hang on to param blocks after we've gone away
  3287.     //
  3288.     UnholdMemory( &printerClassRecord, sizeof(struct usbPrinterPBStruct) );
  3289.  
  3290.     USBExpertStatusLevel(4, printerClassRecord.deviceRef, "\p"kStrPrinterClass"Ready for removal", 0);
  3291.     return kUSBNoErr;
  3292. }
  3293.  
  3294. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  3295.     Name:        CFMInitialization
  3296.  
  3297.     Input Parameters:    
  3298.         initBlock
  3299.         
  3300.     Output Parameters:
  3301.         printerClassDriverFileSpec        set global
  3302.         
  3303.     Description:
  3304.         We use the code fragment initialization to get our filespec which 
  3305.         LoadResources will use to open our resource fork.
  3306.         
  3307.         A peculiarity of the USB 1.0 implementation is that does not lock the
  3308.         driver into physical memory. As a result a driver which does not call
  3309.         SetDriverClosureMemory on it's fragment will likely be paged in during
  3310.         interrupt time and a double bus-fault will occur. The solution for this
  3311.         is to have the USB Expert call SetDriverClosureMemory in a future release
  3312.         of the USB stack. In the meantime, we call it on ourselves to lock us into
  3313.         physical memory. When the USB stack is revved, one call to SetDriverClosureMemory
  3314.         (either this one or the Expert's) will be treated as a NOP.
  3315.  
  3316.  
  3317.  
  3318.  
  3319. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  3320. OSErr
  3321. CFMInitialization( CFragInitBlock *initBlock )
  3322. {
  3323.     //
  3324.     //    get a reference to our file so that we can open up the resource fork later on
  3325.     //
  3326.     if ( CFragHasFileLocation( initBlock->fragLocator.where ) )
  3327.         printerClassDriverFileSpec = *(initBlock->fragLocator.u.onDisk.fileSpec);
  3328.  
  3329.     return noErr;
  3330.  
  3331. }
  3332.  
  3333. // eof
  3334.